冒泡排序、选择排序、插入排序详解:时间复杂度、空间复杂度、稳定性全面分析
创作时间:
作者:
@小白创作中心
冒泡排序、选择排序、插入排序详解:时间复杂度、空间复杂度、稳定性全面分析
引用
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 次遍历
热门推荐
做烤瓷牙前要进行哪些口腔检查?如何避免烤瓷牙修复后出现后遗症?
脾气大易怒情绪容易失控为什么
抑郁症的7种类型,你了解多少?
多感官教学:一种创新的教育方法
从魔童到英雄:哪吒2爆火背后的文化觉醒与价值重构
鸣潮宝可梦+圣遗物?《鸣潮》奏鸣测试深骸最全解析!
《CS2》设备配置要求一览
实验室常用过滤膜规格对比:25mm、47/50mm、90mm过滤膜的应用差异
澳国立环境与资源经济学硕士项目详解
澳国立环境与资源经济学硕士介绍
纳米烤瓷牙和全瓷牙的区别:从材料到效果的全面解析
红楼梦中贾府的生活变化有多大?贾母为何不精细一点?
长安CS75安全气囊故障灯亮了怎么办
你喝的奶未必是“真牛奶”!挑选牛奶的“门道”在这里
如何开发硬件驱动程序
杭州告别共有产权房,配售型保障房时代来临!
24小时汽车救援拖车价格全解析
操作系统笔记之进程调用API中的getpid、fork、wait、exec补充
车失控撞孕妇怎么办
梨花最晚又凋零,何事归期无定准。16句梨花古诗词,既漂亮又多情
绿黄红竖条国旗:马里的文化与历史象征
胰头占位的五种可能原因及治疗方法
莫言《晚熟的人》:扒光了人性的15句话,句句扎心
牙齿补牙一般多少钱?100元起!一文读懂补牙费用与影响因素
补牙要用什么材料?价格是多少?
退热贴是智商税?临床数据告诉你退热贴到底有没有退热效果!
深圳:让城市“会呼吸、有韧性、更宜居”
《计算机视觉》——图像拼接
无证酒驾处罚最新标准判刑多少
罗马教廷烧死布鲁诺带来的启示——科学是开启遏制宗教狂热的处方良药