十大排序算法总结更新
十大排序算法总结
一、冒泡排序
- 身世曰:冒泡排序可以誉为程序员跨入算法门槛的第一步,相信大家一定被冒泡排序一直萦绕在耳边。【且听冒泡吟】,冒泡乃排序家族之太上长老,掌门人不为过之。
- 闻之也:冒泡排序(Bubble Sort),乃计算机科学领域排序算法的简简易者。
- 知其身:它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。【百度百科】
- 名由来:这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。【百度百科】
附实录
/* * 对数组a中的元素排序,改良时间复杂度,空间换时间,冗余flag变量 */ public static void bubbleSort(Integer[] a) { for (int i = 0; i < a.length - 1; i++) { // 外层循环,负责控制比较趟数 // 标志位,记录本趟循环是否进行了交换(即是否整体已经有序) boolean flag = false; for (int j = 0; j < a.length - 1 - i; j++) { // 内层循环,比较为冒泡的数 if (greater(a[j], a[j + 1])) { exch(a, j, j + 1); flag = true; // 记录已经交换过 } } if (!flag) break; // 本趟未交换,已经有序退出外层循环 } }
知论之
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
赞曰
- 时间复杂度
- 最优:O(n) ,若待排序序列和期望序列顺序一致,则只许挨着扫描
- 最坏:O(n^2)
二、选择排序
- 身世曰:冒泡排序可以誉为程序员跨入算法门槛的第一步,相信大家一定被冒泡排序一直萦绕在耳边。【且听冒泡吟】,冒泡乃排序家族之太上长老,掌门人不为过之。
- 闻之也:冒泡排序(Bubble Sort),乃计算机科学领域排序算法的简简易者。
- 知其身:它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。【百度百科】
- 名由来:这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。【百度百科】
附实录
归并排序
归并排序乃二分法、递归值精华结合之。
概念:归并排序是一种分治的思想,将大问题拆解成为小问题,将一个大的数组先拆分成几个小的数组,然后再一点点的合并。
摘要:其排序思路中和快速排序算法一样使用到了递归的思想,同时在归并排序中还用到了一个算法,就是有序数组合并算法。配合递归与有序数组合并算法,归并排序能够高效且稳定的完成排序,归并排序的优点在于其时间复杂度低,稳定性高,但是缺点也是有的,那就是空间复杂度很高。
我们可以总结出归并排序的算法思路,那就是在将整个数组进行不断划分,知道划分的每个字数组的长度为0或者为1,这是每个字数组统统都是有序数组,这是再按照有序数组的拼接算法,对每个子数组进行拼接,这样就能保证每次的拼接结果都还是有序的最终拼接成一个之后,整个数组便都是有序的,而数组的排序也宣布完成,关于这个字数组的划分,实际上是通过递归实现的逻辑上的划分,接下来我们使用动图来看看这个排序过程:
归并排序的实现
public static void mergeSort(int[] arr,int left,int right){ if(left>=right){ return; } int mid = (left + right) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid+1, right); //上边为拆分过程 }
对于拆分过程实际上就是递归,我们不断进行左右的递归,并不断减小子数组的规模,最终便会减小到每个数组的规模为1或者为0,这里需要注意的是递归出口的判断条件为:left>=right,我们为什么不写成leftright呢?这是因为在右递归中,我们的左边界为mid+1,我们的mid是通过直接整除2得到的,当数组规模为1的时候,mid的运算结果为0,此时进入下一层递归时,左递归的左右边界都是0,下层左递归正常退出,但是右递归这是便出现了问题,这是右递归中的right = mid + 1,为1,如果使用leftright,就无法判断并终止这个情况了,所有此时我们还要加入一个新情况,那就是left>right,所以我们合写为left>=right。
之后我们来探讨合并的过程,在合并的时候我们需要使用到一个额外空间,在合并时,我们需要先将合并结果存放在那个额外的新空间上,然后再将新空间上的结果复制回我们的当前数组位置上,我们下面用一个例子来介绍,如图所示:
整体代码如下所示:
static int ans = 0; public int InversePairs(int [] array) { mergeSort(array, 0, array.length - 1); return ans; } // 进行拆分 static void mergeSort(int [] array, int lt, int rt) { // 终止条件 if (lt >= rt) return; int mid = lt + (rt - lt >> 1); mergeSort(array, lt, mid); mergeSort(array, mid + 1, rt); mergeSort(array, lt, mid, rt); } // 进行合并 static void mergeSort(int [] array, int lt, int mid, int rt) { int[] tmp = new int[rt - lt + 1]; // 临时数组,长度为需要合并的数组长度 int lt1 = lt, rt1 = mid; int lt2 = mid + 1, rt2 = rt; int idx = 0; while(lt1 <= rt1 && lt2 <= rt2) { tmp[idx++] = array[lt1] < array[lt2] ? array[lt1++] : array[lt2++]; } // 将有剩余的一边归入tmp while(lt1 <= rt1) tmp[idx++] = array[lt1++]; while(lt2 <= rt2) tmp[idx++] = array[lt2++]; // 将tmp数组赋值到array中 for (int i = 0; i < tmp.length; i++){ array[lt + i] = tmp[i]; } }
练习题:
题目:BM20数组中的逆序对、剑指 Offer 51. 数组中的逆序对
优化归并:
public int[] MySort (int[] arr) { // write code here int left = 0, right = arr.length - 1; merge(left, right, arr); return arr; } // 分 void merge(int left, int right, int[] arr) { if (left >= right) { return; } int mid = left + (right - left >> 1); merge(left, mid, arr); merge(mid + 1, right, arr); // 优化,左右两边都有序且相对有序,则直接复制 if (arr[mid] <= arr[mid + 1]) { System.arraycopy(arr, left, arr, left, right - left + 1); return; } cure(left, mid, right, arr); } // 治 void cure(int left, int mid, int right, int[] arr) { // 临时数组长度为当前区间长度 int[] tmp = new int[right - left + 1]; int idx = 0; int l1 = left, r1 = mid; int l2 = mid + 1, r2 = right; while (l1 <= r1 && l2 <= r2) { tmp[idx++] = arr[l1] < arr[l2] ? arr[l1++] : arr[l2++]; } // 判断两边的剩余数,先左后右 while (l1 <= r1) { tmp[idx++] = arr[l1++]; } while (l2 <= r2) { tmp[idx++] = arr[l2++]; } // 赋值给arr数组 for (int i : tmp) { arr[left++] = i; System.out.println(left); } }
附录
具者类也:排序算法公用(交换和比较)
public static class CommonSortUtils { /* 数组元素 i 和 j 交换位置方法 * */ public static void exch(Comparable[] a, int i, int j) { Comparable temp; temp = a[i]; a[i] = a[j]; a[j] = temp; } /* * 比较是否a > b的方法 * */ public static boolean greater(Comparable a, Comparable b) { return a.compareTo(b) > 0; } /* * 比较是否a < b的方法 * */ public static boolean less(Comparable a, Comparable b) { return b.compareTo(a) > 0; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY