【恋上数据结构】冒泡排序、选择排序、堆排序
冒泡、选择、堆排序
- 前言
- 冒泡排序
- 冒泡排序-优化1
- 冒泡排序-优化2
- 复杂度与稳定性
- 选择排序
- 复杂度与稳定性
- 堆排序
- 堆排序图解
- 堆排序实现
- 复杂度与稳定性
经典的十大排序算法!
前言
请务必看一下这个:排序算法前置知识+代码环境准备。
当上面的内容都准备好以后,那就从冒泡排序开始吧。
冒泡排序
冒泡排序也叫做起泡排序。
执行流程
- ① 从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置
执行完一轮后,最未尾那个元素就是最大的元素。 - ② 忽略①中曾经找到的最大元素,重复执行步骤①,直到全部元素有序。
这是一个标准的冒泡排序。
/*** 冒泡排序-无优化*/
public class BubbleSort1<T extends Comparable<T>> extends Sort<T>{@Overrideprotected void sort() {for (int end = array.length - 1; end > 0; end--) {for (int begin = 1; begin <= end; begin++) {if (cmp(begin, begin - 1) < 0) {swap(begin, begin - 1);}}}}}
冒泡排序-优化1
这个优化并不会提高冒泡排序的平均性能,只是针对极端条件进行处理。
如果序列已经完全有序,可以提前终止冒泡排序。
/*** 冒泡排序-优化1* 如果序列已经完全有序,可以提前终止冒泡排序*/
public class BubbleSort2<T extends Comparable<T>> extends Sort<T>{@Overrideprotected void sort() {for (int end = array.length - 1; end > 0; end--) {boolean sorted = true;for (int begin = 1; begin <= end; begin++) {if (cmp(begin, begin - 1) < 0) {swap(begin, begin - 1);sorted = false;}}if (sorted) break;}}}
冒泡排序-优化2
这个优化是在优化1的基础上,增大极端条件的范围,从完全有序变为尾部局部有序。
如果序列尾部已经局部有序,可以记录最后1次交换的位置,减少比较次数。
/*** 冒泡排序-优化2* 如果序列尾部已经局部有序,可以记录最后1次交换的位置,减少比较次数*/
public class BubbleSort3<T extends Comparable<T>> extends Sort<T>{@Overrideprotected void sort() {for (int end = array.length - 1; end > 0; end--) {// 设为1是因为:如果这轮遍历一次交换都没进行// 则说明序列后面已经有序, 则 end = sortedIndex = 1// end--后等于0,会直接跳出循环int sortedIndex = 1; for (int begin = 1; begin <= end; begin++) {if (cmp(begin, begin - 1) < 0) {swap(begin, begin - 1);// 记录最后1次交换的位置,减少比较次数sortedIndex = begin;}}end = sortedIndex;}}}
复杂度与稳定性
再强调一下,请务必看一下这个:排序算法前置知识+代码环境准备。
最坏、平均时间复杂度: O(n2)O(n^2)O(n2)
最好时间复杂度: O(n)O(n)O(n)
空间复杂度: O(1)O(1)O(1)
冒泡排序属于 In-place
冒泡排序属于稳定的排序算法
稍有不慎,稳定的排序算法也能被写成不稳定的排序算法,比如下面的冒泡排序代码是不稳定的。
选择排序
执行流程:
- ① 从序列中找出最大的那个元素,然后与最未尾的元素交换位置
执行完一轮后,最未尾的那个元素就是最大的元素。 - ② 忽略①中曾经找到的最大元素,重复执行步骤①。
/*** 选择排序*/
public class SelectionSort<T extends Comparable<T>> extends Sort<T> {@Overrideprotected void sort() {for (int end = array.length - 1; end > 0; end--) {int max = 0;for (int begin = 1; begin <= end; begin++) {if (cmp(max, begin) < 0) {max = begin;}}swap(max, end);}}}
生成 20000 个取值在[1, 10000] 的随机数进行排序:
选择排序的交换次数要远远少于冒泡排序,平均性能优于冒泡排序。
复杂度与稳定性
- 最好、最坏、平均时间复杂度:O(n2)O(n^2)O(n2)
- 空间复杂度:O(1)O(1)O(1)
- 选择排序属于不稳定排序
选择排序是否还有优化的空间?
- 使用堆来选择最大值,可以大大提高选择速度。
堆排序
堆排序的前提是了解 堆的知识点。
执行流程:
- ① 对序列进行原地建堆(heapify)
- ② 重复执行以下操作(依次取出堆中最大值,并删除),直到堆的元素数量为 1
- 交换堆顶元素与堆尾元素(把最大值放到最后面)
- 堆的元素数量减 1(不管最后已经放到最后的最大值)
- 对 0 位置进行 1 次 siftDown 操作
堆排序图解
对 {50, 21, 80, 43, 38, 14} 进行原地建堆。
重复执行以下操作,直到堆的元素数量为 1:
- 交换堆顶元素与尾元素
- 堆的元素数量减 1
- 对 0 位置进行 1 次 siftDown 操作
堆排序实现
原地建堆:自下而上的下滤建堆。
下滤:其实就是堆删除元素后,恢复堆的性质。
完整源码:
/*** 堆排序*/
public class HeapSort<T extends Comparable<T>> extends Sort<T> {private int heapSize; // 堆大小@Overrideprotected void sort() {// 原地建堆(自下而上的下滤)heapSize = array.length;for (int i = (heapSize >> 1) - 1; i >= 0; i--) {siftDown(i);}while (heapSize > 1) {// 交换堆顶元素和尾部元素swap(0, --heapSize);// 对0位置进行siftDown(恢复堆的性质)siftDown(0);}}private void siftDown(int index) {T element = array[index];int half = heapSize >> 1;while (index < half) { // index必须是非叶子节点// 默认是左边跟父节点比int childIndex = (index << 1) + 1;T child = array[childIndex];int rightIndex = childIndex + 1;// 右子节点要存在, 并且比左子节点大if (rightIndex < heapSize && cmp(array[rightIndex], child) > 0) { child = array[childIndex = rightIndex];}// 大于等于子节点if (cmp(element, child) >= 0) break;array[index] = child;index = childIndex;}array[index] = element;}}
生成 20000 个取值在[1, 10000] 的随机数进行排序:
复杂度与稳定性
- 最好、最坏、平均时间复杂度:O(nlogn)O(nlogn)O(nlogn)
- 空间复杂度:O(1)O(1)O(1)
- 堆排序属于不稳定排序
【恋上数据结构】冒泡排序、选择排序、堆排序相关推荐
- 【恋上数据结构】计数排序
计数排序 前言 计数排序-简单实现 实现步骤 代码实现与缺点 计数排序 – 改进 改进-图解 改进-实现 复杂度与稳定性 计数排序-对自定义对象进行排序 经典的十大排序算法! 前言 请务必看一下这个: ...
- 【恋上数据结构】希尔排序
希尔排序 前言 希尔排序思路 实例图解 列的划分思路 步长序列计算代码 希尔排序完整实现 步长序列优化 插入排序优化 复杂度和稳定性 经典的十大排序算法! 前言 请务必看一下这个:排序算法前置知识+代 ...
- 堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记
复习梗概 文章目录 复习梗概 什么是堆思想? 堆排序算法怎么来的? 什么是下滤?代码 什么是建堆?代码 堆排序本体 代码及排序过程输出 和时间复杂度 完整代码 什么是堆思想? 最大堆:树形结构,每一个 ...
- 数据结构(八):排序 | 插入排序 | 希尔排序 | 冒泡排序 | 快速排序 | 简单选择排序 | 堆排序 | 归并排序 | 基数排序 | 外部排序 | 败者树 | 置换-选择排序 | 最佳归并树
文章目录 第八章 排序 一.排序的基本概念 (一)什么是排序 (二)排序的应用 (三)排序算法的评价指标 (四)排序算法的分类 (五)总结 二.插入排序 (一)算法思想 (二)算法实现 (三)算法效率 ...
- 【恋上数据结构】排序算法前置知识及代码环境准备
排序准备工作 何为排序? 何为稳定性? 何为原地算法? 时间复杂度的知识 写排序算法前的准备 项目结构 Sort.java Asserts.java Integers.java Times.java ...
- 02_Python算法+数据结构笔记-冒泡排序-选择排序-插入排序-快排-二叉树
b站视频:路飞IT学城 清华计算机博士带你学习Python算法+数据结构_哔哩哔哩_bilibili 文章目录 #11 排序介绍 #12 冒泡排序介绍 #13 冒泡排序 #14 选择排序 #15 插入 ...
- 《数据结构与算法》实验:排序算法实验比较——选择排序 堆排序
<数据结构与算法>实验和课程Github资源 <数据结构与算法>实验:线性结构及其应用--算术表达式求值 <数据结构与算法>实验:树型结构的建立与遍历 <数据 ...
- 七大排序算法—图文详解(插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序)
作者:渴望力量的土狗 博客主页:渴望力量的土狗的博客主页 专栏:数据结构与算法 工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器--牛客网 点击免费注册和我一起刷题吧 目录 插入排序: ...
- 计数排序及其改进 C++代码实现与分析 恋上数据结构笔记
文章目录 复习梗概 算法思想 基础思想 改进空间复杂度,改进不能对负数进行排序问题 改进稳定性 计数排序时间空间复杂度 计数排序基础版 代码及输出 计数排序第一次改进版 代码及输出 计数排序终极版 代 ...
- 【恋上数据结构与算法 第二季】【04】图-基础实现_遍历_拓扑排序
持续学习&持续更新中- 学习态度:脚踏实地 [恋上数据结构与算法 第二季][04]图-基础实现_遍历_拓扑排序 图的实现方案 邻接矩阵 邻接表 图的基础接口 顶点.边的定义 图的基础实现 图的 ...
最新文章
- php定义常量mypi 3.14,php – Codeigniter 3使用未定义的常量VIEWPATH – 假设’VIEWPATH’...
- 算法小论——第三章 又把新桃换旧符
- java des验证码,Servlet返回验证码
- wps定位对话框快捷键_Word、Excel、PPT快捷键汇总
- Spring Boot Actuator
- WebGL(五)——WEBGL缓冲区,绘制三角形
- 腾讯启动“SaaS技术联盟”联合行业制定互联互通标准
- 第三次被盗:Cream Finance 疑存在漏洞,价值1.3亿美元的密币失窃
- MySQL的show profile(已过时)简介以及该功能在MySQL 5.7中performance_schema中的替代
- c++ map是有序还是无序的_go 学习笔记之数组还是切片都没什么不一样
- 面试系列 | 一个线程OOM,进程里其他线程还能运行么?
- 计算机基础技能应用查询中心,《计算机基础及技能训练》大纲
- 目录操作 递归打印目录 DIR drent
- 循序渐进学Docker pdf
- idea spring boot 修改html等不重启即时生效
- Android 4.4(KitKat)窗口管理子系统 - 体系框架
- java邮件附件名称乱码_Java邮件开发(三):解决附件名为乱码及显示友好名称
- 关于工资、社保、公积金、个人所得税等小常识
- ilove中文_Iloveyou翻译成中文是什么意思
- 利用触发器设计计数器
热门文章
- 12306外包给阿里巴巴、IBM等大企业做是否可行?
- 使用 sync.ErrGroup 实现并发搜索文件
- 在编写mini2440 helloworld驱动遇到的问题
- sql示例_SQL Server Lead功能概述和示例
- sql azure 语法_使用Azure Data Studio从SQL Server数据创建图表
- BZOJ4001[TJOI2015]概率论(数学、期望、生成函数、卡特兰数)
- poj1833 排列
- innerHTML和outerHTML的区别
- 线性表顺序表模板 纯本人手工创造
- Struts2框架学习(二) Action