作者:京东保险 王奕龙
对于小规模数据,我们可以选用时间复杂度为 O(n2) 的排序算法。因为时间复杂度并不代表实际代码的执行时间,它省去了低阶、系数和常数,仅代表的增长趋势,所以在小规模数据情况下, O(n2) 的排序算法可能会比 O(nlogn) 的排序算法执行效率高。不过随着数据规模增大, O(nlogn) 的排序算法是不二选择。本篇我们主要对 O(n2) 的排序算法进行介绍,在介绍之前,我们先了解一下算法特性:
算法特性:
稳定性:经排序后,若等值元素之间的相对位置不变则为稳定排序算法,否则为不稳定排序算法
原地排序:是否借助额外辅助空间
自适应性: 自适应性排序受输入数据的影响,即最佳/平均/最差时间复杂度不等,而非自适应排序时间复杂度恒定
本篇我们将着重介绍插入排序,选择排序和冒泡排序了解即可。
插入排序
插入排序的工作方式像 整理手中的扑克牌一样,即不断地将每一张牌插入到其他已经有序的牌中适当的位置。
插入排序的当前索引元素左侧的所有元素都是有序的:若当前索引为 i,则 [0, i - 1] 区间内的元素始终有序,这种性质被称为 循环不变式,即在第一次迭代、迭代过程中和迭代结束时,这种性质始终保持不变。
不过,这些有序元素的索引位置暂时不能确定,因为它们可能需要为更小的元素腾出空间而向右移动。插入排序的代码实现如下:
private void sort(int[] nums) { for (int i = 1; i < nums.length; i++) { int base = nums[i]; int j = i - 1; while (j >= 0 && nums[j] > base) { nums[j + 1] = nums[j--]; } nums[j + 1] = base; } }
它的实现逻辑是取未排序区间中的某个元素为基准数 base,将 base 与其左侧已排序区间元素依次比较大小,并"插入"到正确位置。插入排序对 部分有序(数组中每个元素距离它的最终位置都不远或数组中只有几个元素的位置不正确等情况)的数组排序效率很高。事实上,当逆序很少或数据量不大(n2和nlogn比较接近)时,插入排序可能比其他任何排序算法都要快,这也是一些编程语言的内置排序算法在针对小数据量数据排序时选择使用插入排序的原因。
算法特性:
空间复杂度:O(1)
原地排序
稳定排序
自适应排序:当数组为升序时,时间复杂度为 O(n);当数组为降序时,时间复杂度为 O(n2)
希尔排序
插入排序对于大规模乱序数组排序很慢,因为它只会交换相邻的元素,所以元素只能一步步地从一端移动到另一端,如果最小的元素恰好在数组的最右端,要将它移动到正确的位置需要移动 N - 1 次。
希尔排序是基于插入排序改进的排序算法,它可以交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。它的思想是使数组中间隔为 h 的元素有序(h 有序数组),如下图为间隔为 4 的有序数组:
排序之初 h 较大,这样我们能将较小的元素尽可能移动到靠近左端的位置,为实现更小的 h 有序创造便利,最后一次循环时 h 为 1,便是我们熟悉的插入排序。这就是希尔排序的过程,代码实现如下:
private void sort(int[] nums) { int N = nums.length; int h = 1; while (h < N / 3) { h = 3 * h + 1; } while (h >= 1) { for (int i = h; i < N; i++) { int base = nums[i]; int j = i - h; while (j >= 0 && nums[j] > base) { nums[j + h] = nums[j]; j -= h; } nums[j + h] = base; } h /= 3; } }
希尔排序更高效的原因是它权衡了子数组的规模和有序性,它也可以用于大型数组。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。
选择排序
选择排序的实现非常简单:每次选择未排序数组中的最小值,将其放到已排序区间的末尾,代码实现如下:
private void sort(int[] nums) { for (int i = 0; i < nums.length; i++) { int min = i; for (int j = i + 1; j < nums.length; j++) { if (nums[j] < nums[min]) { min = j; } } swap(nums, i, min); } } private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
算法特性:
空间复杂度:O(1)
原地排序
非稳定排序:会改变等值元素之间的相对位置
非自适应排序:最好/平均/最坏时间复杂度均为 O(n2)
冒泡排序
冒泡排序通过 连续地比较与交换相邻元素实现排序,每轮循环会将未被排序区间内的最大值移动到数组的最右端,这个过程就像是气泡从底部升到顶部一样,代码实现如下:
public void sort(int[] nums) { for (int i = nums.length - 1; i > 0; i--) { // 没有发生元素交换的标志位 boolean flag = true; for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { swap(nums, j, j + 1); flag = false; } } if (flag) { break; } } } private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
算法特性:
空间复杂度:O(1)
原地排序
稳定排序
自适应排序:经过优化后最佳时间复杂度为 O(n)
巨人的肩膀
《算法导论 第三版》第 2.1 章
《算法 第四版》第 2.1 章
《Hello 算法》第 11 章
排序算法-希尔排序
审核编辑 黄宇
- 随机文章
- 热门文章
- 热评文章
- 数码博主EDC,件件实用,快来看看自己都有吗?
- 戴森 OnTrac 头戴式降噪耳机预售:2000多种自定义外观、续航 55 小时3899元
- 限尺码:Mizuno 美津浓 Wave Creation 20 女子跑鞋
- 要想保持头部的清爽,就选择清扬男士控油清爽洗发露!因为他是专门为男士设计的洗发露!
- 昆仑联通IPO转道北交所,年营收超20亿,AI技术加速渗透进IT服务行业
- 女性压力大 三种心脏病易找上门
- e2studio开发LPS28DFW气压计(2)----水压检测
- 许多医生都没听过的罕见病,她设了国内首个专病门诊
- Profibus DP主站转EtherCAT从站协议网关(JM-DPM-ECT)
- 明天起,这些新规将影响你我生活
- 工欲善其事,必先利其器——什么样的牙刷更好用
- 长征路上学党史丨“红色小上海”福建长汀的生态奇迹
- 打通AI的任督二脉 TE Connectivity搭建224G智慧互连
- 1防风防寒!北京今天晴朗伴大风寒意十足 周末将迎小幅升温
- 2新手如何开始跑步?
- 3在中超联赛赛场北京成都球迷高呼:北京加油,成都雄起
- 4西南地区持续阴雨天气 华北黄淮等地大气扩散条件逐步转差
- 5大雾黄色预警:京津冀等8省市部分地区有大雾 局地强浓雾
- 6春晚、哪吒带动文化经济高燃开年,中国IP大有可为!
- 7课间延长、学籍管理新规……新学期,这些变化与你有关
- 8超80亿美元!中芯国际2024年营收创历史新高,净利润减两成
- 9hyper 内存,Hyper内存:如何监控与优化hyper-v虚拟机的内存使用
- 10洞察:人形机器人传感器产业链概览
- 11敏芯股份营收暴涨超35% MEMS传感器业务全面复苏
- 12年底冲刺,家电换新求“新”更求“质”
- 13AI智算驱动光模块上市公司业绩飙涨!新易盛净利涨3倍
- 1Rab 睿坡 Xenon 2.0 男子保暖夹克
- 2中国移动 流量福利活动 免费领4GB流量券
- 3百亿补贴:Lenovo 联想 小新Pro 16 2022款 锐龙版 16英寸笔记本电脑(R7-6800H、16GB、512GB)
- 4China unicom 中国联通 爆款卡 20年29元月租(160G通用流量+100分钟通话+自主激活+送靓号)返10元红包
- 5联想拯救者 R7000 游戏本增配,搭最新 AMD 锐龙7 8745H + RTX 40 独显6699元起
- 6中国电信:汛期地区欠费用户也能用天通卫星服务
- 7全马跑者推荐,南卡Runner Pro5,跑步必备,骨传导音质天花板,潜艇级防水技术,值得入手
- 8清爽宅家~有台神仙茶吧机~你就会爱上喝水
- 9“宝宝巴士”极氪MIX最新官图公布,预计下半年上市
- 10胶囊收纳难?纠结喝点啥?一个抓娃娃机搞定所有难题!
- 11给大家种草一款护眼神器 米家防蓝光眼镜Pro 复古好看性价比高
- 12广西“八大米粉”排行,螺蛳粉垫底,游客:本地人果然更懂米粉
- 13泡椒鸡爪的家常做法分享