冒泡排序、选择排序、插入排序详解:时间复杂度、空间复杂度、稳定性全面分析
创作时间:
作者:
@小白创作中心
冒泡排序、选择排序、插入排序详解:时间复杂度、空间复杂度、稳定性全面分析
引用
CSDN
1.
https://blog.csdn.net/u013546788/article/details/105671228
排序算法是计算机科学中的基础算法之一,掌握其原理和性能分析对于理解算法设计和优化至关重要。本文详细分析了三种基本排序算法:冒泡排序、选择排序和插入排序,从最好/最坏/平均时间复杂度、稳定性、内存消耗等多个维度进行了深入探讨。
如何分析排序算法
最好、最坏、平均时间复杂度
- 算法的时间复杂度,会随着排序集合的有序性而改变。我们需要分析不同算法在不同数据下的表现
- 最好时间复杂度:在完全有序的情况下的时间复杂度(满有序度)
- 最坏时间复杂度:在最坏情况下的时间复杂度(有序度为0)
内存消耗
- 就是排序算法的空间复杂度
- 原地排序:原地排序算法,就是特指空间复杂度是 O(1) 的排序算法。
算法的稳定性
- 如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。
有序度、逆序度
- 有序度是数组中具有有序关系的元素对的个数
- 逆序度 = 满有序度 - 有序度
- 排序的过程就是一种增加有序度,减少逆序度的过程,最后达到满有序度,就说明排序完成了。
实例
- 对于一个倒序排列的数组,比如 6,5,4,3,2,1,有序度是 0
- 对于一个完全有序的数组,比如 1,2,3,4,5,6,有序度就是 n*(n-1)/2,也就是 15
- 我们把完全有序的数组的有序度叫作满有序度。
冒泡排序的原理和性能分析
原理
- 冒泡排序只会操作相邻的两个数据。
- 冒泡排序会将相邻的两个数据两两比较,如果不符合要求则进行位置交换
- 优化:当某次遍历没有数据交换的时候,则停止排序
代码
// 冒泡排序,a表示数组,n表示数组大小
public void bubbleSort(int[] a) {
if (a.length <= 1) return;
for (int i = 0; i < a.length; ++i) {
// 提前退出冒泡循环的标志位
boolean flag = false;
for (int j = 0; j < a.length - i - 1; ++j) {
if (a[j] > a[j+1]) { // 交换
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
flag = true; // 表示有数据交换
}
}
if (!flag) break; // 没有数据交换,提前退出
}
}
性能分析
- 是否是原地排序算法
- 只进行了比较和交换操作,没有借助额外的空间。
- 是否是稳定的
- 当有相邻的两个元素大小相等的时候,不会交换顺序
- 时间复杂度分析
- 最好:O(n) 完全有序。不需要重排序,只需要进行一次遍历
- 最坏:O(n²) 倒序。需要进行遍历 O(n);每次遍历都需要冒泡,共需要 N 次
- 平均:O(n²)
- 有序度
- 冒泡排序包含两个操作原子,比较和交换。
- 每交换一次,有序度就加 1。不管算法怎么改进,交换次数总是确定的,即为逆序度。
- 平均情况下,需要 n*(n-1)/4 次交换操作,比较操作肯定要比交换操作多,而复杂度的上限是 O(n2),所以平均情况下的时间复杂度就是 O(n2)
- 最坏情况,有序度为0。最好情况,有序度为 (n-1)n/2
插入排序的原理和性能分析
原理
- 将数据集分为了已排序 和 待排序。每次的排序过程就是从待排序中取出一个,插入到已排序中的相应位置
代码
public int[] insertSort(int[] items) {
if (items.length < 1) return items;
for (int i = 1; i < items.length; i++) {
int cur = items[i];
//1. 从未排序的队列,拿出一个
int j = i - 1;
//2. 在已排序的队列,找到合适的位置
for (; j > 0; j--) {
if (items[j] > cur) {
items[j + 1] = items[j];
} else {
//找到位置
break;
}
}
//3. 插入到合适的位置
items[j] = cur;
}
return items;
}
性能分析
- 是否为原地排序
- 是。只是数据的比较和移动
- 是否稳定
- 是。对于值相同的元素,按照先来后到的顺序排列
- 时间复杂度
- 最好:O(n)。完全有序
- 最坏:O(n²)。每次都插入到已排序序列的队头
- 平均:O(n²)。每次插入操作都相当于在数组中插入一个数据,循环执行 n 次插入操作,所以平均时间复杂度为 O(n2)。
选择排序的原理和性能分析
原理
- 也是将数据及分为 已排序 和 待排序 两个区间。
- 排序过程:选取待排序区间中最小/最大的数据,放到已排序区间的队尾(与待排序区间队头交换位置)
代码
public int[] selectSort(int[] items) {
if (items.length < 1) return items;
for (int i = 0; i < items.length; i++) {
int minIndex = i;
for (int j = i; j < items.length - 1; j++) {
if (items[j + 1] < items[j]) {
minIndex = j + 1;
}
}
//swap
if (minIndex != i) {
int tmp = items[i];
items[i] = items[minIndex];
items[minIndex] = tmp;
}
}
return items;
}
性能分析
- 是否为原地排序
- 是
- 是否稳定
- 否,涉及到交换位置。每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置。
- 时间复杂度
- 最好/最坏/平均:O(n²)。即使完全有序,也需要经过 ( n + 1 ) n / 2 次遍历
热门推荐
留学生海外求职必备指南
盐酸替扎尼定制剂及非临床研究
揭秘品牌仿冒案例:如何辨别正品、打击假货
成都楼市“止跌回稳”初见成效,政策放宽对房价影响几何?
深观察|“越界”诉求增多,如何正确拨打12345热线?
电梯日常巡检指南:确保安全与高效运行的关键步骤
CSA发布 | 从原则到实践:动态监管下负责任的人工智能
股市K线三炷香(炒股短线选股技巧)
如何有效应对流鼻血?
高效学习新技能的捷径:掌握快速进步的秘籍
交通事故责任书出来后怎么处理和索赔?
MV背景音乐:选择、创作与版权注意事项
楼房装修顺序(楼房装修顺序是从上往下装吗)
三国杀谋张辽有什么技能 谋张辽技能介绍
高中英语怎么提高听写能力(提升英语听写能力的方法)
丝绸面料怎么清洗 丝绸面料如何保养
早晨嘴巴张不开?小心颞下颌关节紊乱或面神经麻痹!
古代驸马的荣耀与挑战:地位、选拔及婚后生活的探秘
熬夜会影响体检结果吗?从内分泌到血液参数的全面解析
电化学的前世今生:从伏打电堆到新能源革命
铅酸电池的基本结构和工作原理
星星为何悬空不落?宇宙中颠覆常识的引力真相
双相情感障碍:一场情绪的过山车之旅
人民日报:将文明养犬落到实处
最适合家庭保护的十大犬种
原神V5.5瓦雷莎攻略:养成、配队与机制全方位解析
麻山药和铁棍山药的区别?
怎样看待国际黄金价格的季度变化?这种变化对投资决策有何启示?
三相电贵还是两相电贵?家里改三相电的好处
男士休陪产假利与弊分析,3大好处不容忽视