数据结构与算法三 排序算法

  • 1. 选择排序
  • 2. 插入排序
  • 3. 冒泡排序
  • 4. 归并排序
  • 5. 快速排序
  • 6. 希尔排序
  • 7. 堆排序
  • 总结

1. 选择排序

选择排序的基本原理:
对于未排序的一组记录,经过第一次比较,找到最大或者最小值,将它与第一个位置交换,然后除去第一个位置的最大或者最小值,再重复上述过程,直到所有记录排序好。

代码如下:

/*** 描述:选择排序** @author Ye* @version 1.0* @date 2021/8/27 20:08*/
public class TestSort1 {public static void selectSort(int[] a){int min;int temp;int flag = 0;for (int i=0;i<a.length;i++){min = a[i];for (int j=i+1;j<a.length;j++){if (a[j]<min){min = a[j];flag = j;}}temp = a[i];a[i] = min;a[flag] = temp;}}public static void main(String[] args) {int i = 0;int[] a = {5,9,63,87,56,25,41,3,12,69};selectSort(a);for (i=0;i<a.length;i++){System.out.print(a[i] + " ");}System.out.println();}
}

运行截图:

2. 插入排序

对于给定的一组记录,初始时假设第一个记录自成一个有序序列,其余记录为无序序列。然后第二个记录按照记录大小,将当前处理的记录插入到其之前的有序序列中,直至最后一个记录到有序序列为止。

代码如下:

/*** 描述:插入排序** @author Ye* @version 1.0* @date 2021/8/27 20:47*/
public class TestSort2 {public static void insertSort(int[] a){if (a != null){for (int i=1;i<a.length;i++){int temp = a[i];int j = i;if (a[j-1]>temp){while (j>=1&&a[j-1]>temp){a[j] = a[j-1];j--;}a[j] = temp;}}}}public static void main(String[] args) {int[] array = {7,3,19,40,4,7,1};insertSort(array);for (int i=0;i<array.length;i++){System.out.println(array[i] + " ");}}
}

运行截图:

3. 冒泡排序

冒泡排序顾名思义就是整个过程就像气泡一样往上升,单向冒泡的基本思想是(假设由小到大排序):对于给定的n个记录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换位置,进行一轮比较和换位后,n个记录中的最大记录将位于第n位;然后对前(n-1)个记录进行第二轮比较;重复该过程直到进行比较的记录只剩一个为止。

代码示例:

/*** 描述:冒泡排序** @author Ye* @version 1.0* @date 2021/8/28 10:15*/
public class TestSort5 {public static void Bubble(int[] array){int temp;for (int i=0;i<array.length;i++){for (int j=1;j<array.length-i;j++){if (array[j-1]>array[j]){temp = array[j-1];array[j-1] = array[j];array[j] = temp;}}}}public static void main(String[] args) {int[] a = {12,5,6,8,9,4,99,56};Bubble(a);for (int i=0;i<a.length;i++){System.out.println(a[i] + " ");}}
}

运行截图:

4. 归并排序

归并排序是利用递归与分治技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再利用递归方法将排序好的半子表合成越来越大的有序序列。

归并排序算法的原理如下:对于给定的一组记录(n个),首先将每两个相邻的长度为1的子序列进行归并,得到n/2(向上取整)个长度为2或1的有序子序列,在将其两两归并,反复此过程,直到得到一个有序序列。

/*** 描述:归并排序** @author Ye* @version 1.0* @date 2021/8/28 14:31*/
public class TestSort3 {public static void Merge(int[] array,int p,int q,int r){int i,j,k,n1,n2;n1 = q - p + 1;n2 = r - q;int[] L = new int[n1];int[] R = new int[n2];for (i=0,k=p;i<n1;i++,k++){L[i] = array[k];}for (i=0,k=q+1;i<n2;i++,k++){R[i] = array[k];}for (k=p,i=0,j=0;i<n1&&j<n2;k++){if (L[i]>R[j]){array[k] = L[i];i++;}else {array[k] = R[j];j++;}}if (i<n1){for (j=i;j<n1;j++,k++){array[k] = L[j];}}if (j<n2){for (i=j;i<n2;i++,k++){array[k] = R[i];}}}public static void MergeSort(int[] array,int p,int r){if (p<r){int q = (p+r)/2;MergeSort(array,p,q);MergeSort(array,q+1,r);Merge(array,p,q,r);}}public static void main(String[] args) {int i = 0;int[] a = {8,9,6,5,89,3,34};int len = a.length;MergeSort(a,0,len-1);for (i=0;i<len-1;i++){System.out.println(a[i] + " ");}}
}

运行截图:

5. 快速排序

基本原理:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,其中前一部分的所有记录均比后一部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中的所有记录均有序为止。

算法步骤:

  1. 分解。将输入的序列array[m···n]划分成两个非空子序列array[m···k]和array[k+1···n],使用array[m··k]中任一元素的值不大于array[k+1···n]中任一值。
  2. 递归求解。通过递归调用快速排序算法分别对array[m···k]和array[k+1···n]进行排序。
  3. 合并。由于对分解出的两个子序列的排序是就地进行的,所以在array[m···k]和array[k+1···n]都排好序后不需要执行任何array[m···n]就已排好序。

代码示例:


/*** 描述:快速排序** @author Ye* @version 1.0* @date 2021/8/28 18:22*/
public class TestSort4 {public static void sort(int[] array,int low,int high){int i,j;int index;if (low >= high){return;}i = low;j = high;index = array[i];while (i < j){while (i < j && array[j] >= index){j--;}if (i<j){array[i++] = array[j];}while (i<j&&array[i]<index){i++;}if (i<j){array[j--] = array[i];}}array[i] = index;sort(array,low,i-1);sort(array,i+1,high);}public static void quickSort(int[] array){sort(array,0,array.length-1);}public static void main(String[] args) {int i = 0;int[] a = {5,6,9,8,56,34,25,77};int len = a.length;quickSort(a);for (i=0;i<a.length;i++){System.out.print(a[i] + " ");}}
}

运行截图:

6. 希尔排序

基本原理:
先将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个排序序列“基本有序后”,最后再对所有元素进行一次直接插入排序。

具体步骤:

  1. 选择一个步长序列t1,t2,···,tk,满足ti > tj ( i<j ),tk = 1
  2. 按步长序列个数k,对待排序序列进行k趟排序
  3. 每趟排序,根据对应的步长ti,将待排序序列分割成ti个子序列,分别对各个子序列进行直接插入排序。

代码示例:

/*** 描述:希尔排序** @author Ye* @version 1.0* @date 2021/8/28 19:40*/
public class TestSort6 {public static void shellSort(int[] array){int length = array.length;int i,j;int h;int temp;for (h = length/2;h>0;h=h/2){for (i = h;i<length;i++){temp = array[i];for (j=i-h;j>=0;j-=h){if (temp<array[j]){array[j+h] = array[j];}else {break;}}array[j+h] = temp;}}}public static void main(String[] args) {int i = 0;int[] a = {1,12,69,23,64,88,99,51};int len = a.length;shellSort(a);for (i=0;i<len;i++){System.out.println(a[i] + " ");}}
}

运行截图:

7. 堆排序

基本原理:
堆排序的思想是对于给定的n个记录,初始时把这些记录看作一棵顺序存储的二叉树,然后将其调整为一个大顶堆,然后将堆的最后一个元素与堆顶元素(二叉树根结点)进行交换后,堆的最后一个记录即为最大记录;接着将前(n-1)个元素(即不包括最大记录)重新调整为一个大顶堆,再将堆顶元素与当前堆的最后一个元素进行交换后得到次大的记录,重复该过程直到调整的堆中只剩一个元素时为止,该元素即为最小记录,此时可得到一个有序序列。

主要过程:

  1. 构建堆
  2. 交换堆顶元素与最后一个元素的位置

示例代码:


/*** 描述:堆排序** @author Ye* @version 1.0* @date 2021/8/28 21:21*/
public class TestSort7 {public static void adjustMinHeep(int[] a,int pos,int len){int temp;int child;for (temp = a[pos];2*pos +1 <= len;pos = child){child = 2 * pos + 1;if (child<len && a[child] > a[child + 1]){child++;}if (a[child] < temp){a[pos] = a[child];}else {break;}}a[pos] = temp;}public static void myMinHeapSort(int[] array){int i;int len = array.length;for (i = len/2-1;i >= 0;i--){adjustMinHeep(array,i,len-1);}for (i = len - 1;i >= 0;i--){int temp = array[0];array[0] = array[i];array[i] = temp;adjustMinHeep(array,0,i-1);}}public static void main(String[] args) {int i = 0;int[] a = {89,63,54,12,35,95,64,19,39,88};int len = a.length;myMinHeapSort(a);for (i = 0; i<len;i++){System.out.println(a[i] + " ");}}
}

运行截图:

总结

算法性能对比

排序算法 最好时间 平均时间 最坏时间 辅助存储 稳定性 备注
简单选择排序 O(n^2) O(n^2) O(n^2) O(1) 不稳定 n小时比较好
直接插入排序 O(n) O(n^2) O(n^2) O(1) 稳定 大部分已有序时较好
冒泡排序 O(n) O(n^2) O(n^2) O(1) 稳定 n小时比较好
希尔排序 O(n) O(nlogn) O(n^s) 1<s<2 O(1) 不稳定 s是所选分组
快速排序 O(nlogn) O(nlogn) O(n^2) O(logn) 不稳定 n大时比较好
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 n大时比较好
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 n大时比较好

结论:

  1. 简单地说,所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,就称这种排序方法是稳定的,反之,就是非稳定的,例如,一组数排序前是 a1,a2,a3,a4,a5,其中 a2 =a4,经过某种排序后 a1,a2,a4,a3,a5,则说这种排序是稳定的,因为a2 排序前在 a4 的前面,排序后它还是在 a4 的前面。假如变成 a1,a4,a2,a3,a5 就不是稳定的了。各种排序算法中稳定的排序算法有直接插入排序、冒泡排序和归并排序,而不稳定的排序算法有希尔排序、快速排序、简单选择排序和堆排序。
  2. 时间复杂度为 O(n^2)的排序算法有直接插入排序、冒泡排序、快速排序和简单选择排序;时间复杂性为 O(nlogn)的排序算法有堆排序和归并排序。
  3. 空间复杂度为 O(1)的算法有简单选择排序、直接插入排序、冒泡排序、希尔排序和堆排序,空间复杂度为 O(n)的算法是归并排序,空间复杂度为 O(logn)的算法是快速排序。
  4. 虽然直接插入排序和冒泡排序的速度比较慢,但是当初始序列整体或局部有序时,这两种排序算法会有较高的效率。当初始序列整体或局部有序时,快速排序算法的效率会下降。当排序序列较小且不要求稳定性时,直接选择排序效率较好;要求稳定性时,冒泡排序效率较好。

参考:《Java程序员面试笔试宝典》 何昊、薛鹏、叶向阳 编著

数据结构与算法(三) 排序算法(代码示例)相关推荐

  1. 送书 | 你一定能看懂的算法基础书(代码示例基于Python)

    本文引自图灵教育<算法图解> 你一定能看懂的算法基础书:代码示例基于Python:400多个示意图,生动介绍算法执行过程:展示不同算法在性能方面的优缺点:教会你用常见算法解决每天面临的实际 ...

  2. 数据结构排序算法实验报告_[数据结构与算法系列]排序算法(二)

    我的上一篇文章向大家介绍了排序算法中的冒泡排序.插入排序和选择排序.它们都是平均时间复杂度为 O(n^2) 的排序算法,同时还为大家讲解了什么是原地排序和什么是排序的稳定性.下图是这三种算法的比较,不 ...

  3. 数据结构与算法之排序算法

    数据结构与算法之排序算法 排序算法的介绍 ​ 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程. 排序的分类 1)内部排序:指将需要处理的数据都加载到内部 ...

  4. 大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 21

    大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 211 第 ...

  5. python结构排序_Python数据结构(七)排序算法 上

    Python数据结构(七)排序算法 上 上回: 本文的重点不是代码,而是带着大家分析每一个排序算法背后的思想以及使用到的数据结构.很多时候不是我们想不出算法该如何去写,而是题目并没有指定特定的数据结构 ...

  6. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  7. 算法---比较排序算法

    在大批量的刷题之前,做好前期的准备工作,首先明白了时间复杂度和空间复杂度的计算方法,这个在我的上一篇博文里有提到,然后对经典排序算法做一个全面了解,2017.7.13,本文大部分内容引自http:// ...

  8. c++ 二维数组 排序_【算法】排序算法之计数排序

    前几回,我们已经对[算法]排序算法之冒泡排序.[算法]排序算法之插入排序.[算法]排序算法之希尔排序.[算法]排序算法之选择排序.[算法]排序算法之快速排序.[算法]排序算法之归并排序.[算法]排序算 ...

  9. 查找算法与排序算法之Python实现

    查找算法与排序算法 查找算法 顺序查找 二分查找 排序算法 冒泡排序 选择排序 简单选择排序 选择排序 插入排序 快速排序 堆排序 堆排序topk问题 归并排序 希尔排序 计数排序 桶排序 基数排序 ...

最新文章

  1. xftp不能上传文件到服务器,xftp传文件到云服务器
  2. 谈谈金融行业的开源风险管理
  3. Mongdb中常用的数据清洗
  4. Audio Driver 架构
  5. 04:AD采样【MSP430F5529】
  6. GAMES101-现代计算机图形学入门-闫令琪——Lecture 18 Advanced Topics in Rendering
  7. 影像自动解译_遥感影像的解译-分类
  8. FPA色彩性格测试题:黄 红 蓝 绿 你是哪个?
  9. docker 20.10.9 dockerd containerd containerd-shim-runc-v2 runc 组件分析
  10. 思六方武学《国际教练武才友创立》
  11. Python实现行业轮动量化选股【附完整源码】
  12. 2022年全球市场智能室内空气质量检测仪总体规模、主要生产商、主要地区、产品和应用细分研究报告
  13. Oracle导入.DMP文件命令
  14. Runc 容器初始化和容器逃逸
  15. FCS阅读笔记:良好的编程习惯
  16. 如何预防账号密码泄露等安全问题
  17. 跨境电商可以学习的5个推荐活动
  18. 【强化学习】迷宫寻宝:Sarsa和Q-Learning
  19. 2020年终总结(苦难与坚韧并行)
  20. LX12864P1屏幕使用介绍(ST7567驱动),显示横线、字符、图形

热门文章

  1. 阿里云MVP北京闭门会圆满落幕 多把“利剑”助力开发者破阵蜕变...
  2. Laravel5.4中文分词搜索-使用 Laravel Scout,Elasticsearch,ik 分词(三)
  3. AD7606八通道AD采集模块测试
  4. Python骚操作:Python控制Excel实现自动化办公!
  5. 网易云音乐web/网页版无法播放问题
  6. 在ubuntu11.10上安装6款顶级漂亮的BURG主题
  7. mysqldump加速导入参数说明
  8. 拉格朗日乘数法 和 KTT条件
  9. jzoj. 3518. 【NOIP2013模拟11.6A组】进化序列(evolve)
  10. MySQL知识点整理汇总