各种排序算法的时间复杂度和稳定性,快排的原理

本文介绍了多种排序算法,包括插入排序、希尔排序、冒泡排序及其改进、快速排序、选择排序、堆排序、归并排序和基数排序。详细阐述了各算法的原理,如插入排序是将待排序数据插入有序序列,冒泡排序通过交换使大数后移等。

https://blog.youkuaiyun.com/shihuboke/article/details/79387523

排序图表:

一、插入排序

  每次将一个待排序的数据,跟前面已经有序的序列的数字一一比较找到自己合适的位置,插入到序列中,直到全部数据插入完成。

 

二、希尔排序

  先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。由于希尔排序是对相隔若干距离的数据进行直接插入排序,因此可以形象的称希尔排序为“跳着插”

 

三、冒泡排序

  通过交换使相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就“沉”到最后面了。重复N次即可以使数组有序。

  

  冒泡排序改进1:在某次遍历中如果没有数据交换,说明整个数组已经有序。因此通过设置标志位来记录此次遍历有无数据交换就可以判断是否要继续循环。

  

  冒泡排序改进2:记录某次遍历时最后发生数据交换的位置,这个位置之后的数据显然已经有序了。因此通过记录最后发生数据交换的位置就可以确定下次循环的范围了。

 

四、快速排序

  “挖坑填数+分治法”,首先令i =L; j = R; 将a[i]挖出形成第一个坑,称a[i]为基准数。然后j--由后向前找比基准数小的数,找到后挖出此数填入前一个坑a[i]中,再i++由前向后找比基准数大的数,找到后也挖出此数填到前一个坑a[j]中。重复进行这种“挖坑填数”直到i==j。再将基准数填入a[i]中,这样i之前的数都比基准数小,i之后的数都比基准数大。因此将数组分成二部分再分别重复上述步骤就完成了排序。

 

五、选择排序

   数组分成有序区和无序区,初始时整个数组都是无序区,然后每次从无序区选一个最小的元素直接放到有序区的最后,直到整个数组变有序区。

 

六、堆排序

     图:

 

   堆的插入就是——每次插入都是将新数据放在数组最后,而从这个新数据的父结点到根结点必定是一个有序的数列,因此只要将这个新数据插入到这个有序数列中即可。

   堆的删除就是——堆的删除就是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最小的,如果父结点比这个最小的子结点还小说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点开始将一个数据在有序数列中进行“下沉”。

   因此,堆的插入和删除非常类似直接插入排序,只不是在二叉树上进行插入过程。所以可以将堆排序形容为“树上插”

 

七、归并排序

   归并排序主要分为两步:分数列(divide),每次把数列一分为二,然后分到只有两个元素的小数列;合数列(Merge),合并两个已经内部有序的子序列,直至所有数字有序。用递归可以实现。

 

八、基数排序(桶排序)

    基数排序,第一步根据数字的个位分配到每个桶里,在桶内部排序,然后将数字再输出(串起来);然后根据十位分桶,继续排序,再串起来。直至所有位被比较完,所有数字已经有序。

   

 

谢谢!!!
 

<think> 我们被要求回答八大排序算法时间复杂度稳定性问题。首先,我们需要明确八大排序算法通常指的是:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序基数排序。 接下来,我们将逐一列出每种排序算法时间复杂度稳定性,并尽可能给出简要说明。 注意:稳定性是指如果两个相等的元素在排序前后的相对位置不变,则该排序算法是稳定的。 1. 冒泡排序(Bubble Sort) - 时间复杂度: - 最好情况(已有序):$O(n)$ - 最坏情况(逆序):$O(n^2)$ - 平均情况:$O(n^2)$ - 稳定性:稳定。因为相邻元素比较交换,相等元素不会交换。 2. 选择排序(Selection Sort) - 时间复杂度: - 最好、最坏、平均情况均为$O(n^2)$(因为每次都要遍历未排序部分找最小/最大) - 稳定性:不稳定。例如序列[5, 5, 2],第一次选择最小元素2第一个5交换,导致两个5的相对位置改变。 3. 插入排序(Insertion Sort) - 时间复杂度: - 最好情况(已有序):$O(n)$ - 最坏情况(逆序):$O(n^2)$ - 平均情况:$O(n^2)$ - 稳定性:稳定。每次将元素插入到已排序序列的适当位置,遇到相等元素则插入在后面,相对位置不变。 4. 希尔排序(Shell Sort) - 时间复杂度:与增量序列的选择有关,最坏情况为$O(n^2)$,好的增量序列如Hibbard可以使最坏情况达到$O(n^{3/2})$,平均情况则根据增量序列不同而不同,一般在$O(n^{1.3})$到$O(n^2)$之间。 - 稳定性:不稳定。因为分组插入排序可能导致相等元素跨越交换。 5. 归并排序(Merge Sort) - 时间复杂度:最好、最坏、平均情况均为$O(n \log n)$ - 稳定性:稳定。归并遇到相等元素,优先取前面的子序列中的元素。 6. 快速排序(Quick Sort) - 时间复杂度: - 最好情况(每次划分均衡):$O(n \log n)$ - 最坏情况(每次划分极不均衡,如已有序):$O(n^2)$ - 平均情况:$O(n \log n)$ - 稳定性:不稳定。因为partition过程中,相等的元素可能因为交换而改变相对位置。例如[3, 2, 2, 4],以3为基准,后面的2可能与前面的2交换位置(取决于具体实现)。 7. 堆排序(Heap Sort) - 时间复杂度:建堆$O(n)$,调整堆$O(n \log n)$,所以整体为$O(n \log n)$(最好、最坏、平均)。 - 稳定性:不稳定。堆调整过程中,父节点子节点的交换可能破坏相等元素的相对位置。例如[5, 5, 5],在堆调整过程中,第一个5与最后一个5交换,导致相对位置改变。 8. 基数排序(Radix Sort) - 时间复杂度:$O(d(n+k))$,其中d是最大数字的位数,k是基数(每一位的取值范围)。通常k较小(如0-9),所以近似线性。 - 稳定性:稳定。基数排序按位排序,必须使用稳定的排序算法(通常用计数排序),所以整体稳定。 注意:基数排序不是基于比较的排序,因此它的时间复杂度可以突破$O(n\log n)$。 我们将以上信息整理成表格如下: | 排序算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 稳定性 | |------------|----------------|---------------|---------------|-------------|--------| | 冒泡排序 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 | | 选择排序 | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | $O(1)$ | 不稳定 | | 插入排序 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 | | 希尔排序 | $O(n^{1.3})$左右 | $O(n)$ | $O(n^2)$ | $O(1)$ | 不稳定 | | 归并排序 | $O(n \log n)$ | $O(n \log n)$ | $O(n \log n)$ | $O(n)$ | 稳定 | | 快速排序 | $O(n \log n)$ | $O(n \log n)$ | $O(n^2)$ | $O(\log n)$ | 不稳定 | | 堆排序 | $O(n \log n)$ | $O(n \log n)$ | $O(n \log n)$ | $O(1)$ | 不稳定 | | 基数排序 | $O(d(n+k))$ | $O(d(n+k))$ | $O(d(n+k))$ | $O(n+k)$ | 稳定 | 注意:希尔排序的时间复杂度与增量序列的选择密切相关,上述平均时间复杂度是一个经验值,没有统一结论。 最后,根据用户要求,我们生成相关问题。 </think> ### 八大排序算法时间复杂度稳定性对比 以下是主要排序算法时间复杂度稳定性分析总结表: | 排序算法 | 平均时间复杂度 | 最佳时间复杂度 | 最差时间复杂度 | 空间复杂度 | 稳定性 | 说明 | |--------------|----------------|----------------|----------------|------------|--------|------| | **冒泡排序** | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定✅ | 相邻元素比较交换 | | **选择排序** | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | $O(1)$ | 不稳定❌ | 最小元素交换到前面 | | **插入排序** | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定✅ | 构建有序序列 | | **希尔排序** | $O(n^{1.3})$ | $O(n\log n)$ | $O(n^2)$ | $O(1)$ | 不稳定❌ | 分组插入排序 | | **归并排序** | $O(n\log n)$ | $O(n\log n)$ | $O(n\log n)$ | $O(n)$ | 稳定✅ | 分治法 | | **快速排序** | $O(n\log n)$ | $O(n\log n)$ | $O(n^2)$ | $O(\log n)$| 不稳定❌ | 基准元素分区 | | **堆排序** | $O(n\log n)$ | $O(n\log n)$ | $O(n\log n)$ | $O(1)$ | 不稳定❌ | 二叉堆结构 | | **基数排序** | $O(d(n+k))$ | $O(d(n+k))$ | $O(d(n+k))$ | $O(n+k)$ | 稳定✅ | 按位分配收集 | #### 关键说明: 1. **稳定性定义**: 排序后相等元素的相对位置保持不变即为稳定排序。例如: ```python # 原始序列 [(5,A), (3,B), (5,C)] ``` 稳定排序后:`[(3,B), (5,A), (5,C)]`(5的相对位置不变)[^1] 2. **时间复杂度对比**: - 平方级:冒泡/选择/插入排序 - 线性对数级:归并/快速/堆排序 - 线性级:基数排序($d$为最大位数) 3. **稳定性规律**: - 相邻元素比较的排序通常稳定(冒泡、插入) - 元素跳跃交换的排序通常不稳定(选择、希尔、堆) - 分治法排序取决于实现(归并稳定,快排不稳定) #### 快速排序示例(不稳定) ```python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[0] # 相等元素可能被分到不同分区 left = [x for x in arr[1:] if x <= pivot] right = [x for x in arr[1:] if x > pivot] return quick_sort(left) + [pivot] + quick_sort(right) ``` #### 归并排序示例(稳定) ```python def merge(left, right): result = [] i = j = 0 while i < len(left) and j < len(right): # 相等优先取左序列元素 if left[i] <= right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result.extend(left[i:]) result.extend(right[j:]) return result ``` > 注:某些算法在不同实现下可能改变稳定性,如将快速排序的`<=`改为`<`可变为稳定,但会牺牲效率[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值