冒泡排序
简述
原理是相邻的两两元素做比较并往后移动,每轮可以选出一个最值
故最多n-1轮排完
每轮最多比较n-1-已完成轮数次
总共最多比较n*(n-1)/2次
比较并交换可以通过中间变量暂存交换值来处理
基本冒泡排序
/** * 冒泡排序 * 时间复杂度On2,空间复杂度O1 * 执行n-1轮 * 每轮比较n-1-i次,总共比较n*(n-1)/2次 * 最大交换n*(n-1)/2次——最坏情况:倒序 * @author 夜神 */ public class BubSort { /** * 向前比较 int j=arr.length-1;j>i;j-- * @param arr */ public static void forwardSort(int[] arr){ int tmp=0; int count=0; // 总共比较次数,也是最大交换次数(最坏情况:倒序) int compare=0; // n-1轮排完序,i控制轮数,隐含已经排好序的个数 for(int i=0;i<arr.length-1;i++){ // 每轮比较n-1-i次 前序排列写法,往前面比较 for (int j=arr.length-1;j>i;j--){ compare++; // 这里比较关系用的<,选取的是小值 小的向前移,拍好的在左边 if (arr[j]<arr[j-1]){ tmp=arr[j]; arr[j]=arr[j-1]; arr[j-1]=tmp; count++; } } } System.out.println(Arrays.toString(arr)); System.out.println("交换"+count+"次"); System.out.println(compare+"次比较"); } /** * 向后比较 * 次数那里的另外一种写法 j<arr.length-1-i j从0开始,后续排列 * @param arr */ public static void backwardsSort(int[] arr){ // 交换次数 int count=0; // 总共比较次数,也是最大交换次数(最坏情况:倒序) int compare=0; int tmp; // n-1轮 i 属于[0,n-1),即[0,n-2] for (int i=0;i<arr.length-1;i++){ // 每轮比较n-1-i次 总共(n-1)-0+(n-1)-1+(n-1)-2+....=(n-1)*(n-1)-(0+1+2+...+n-1-1)=(n-1)*(n-1)-(n-2)*(n-1)/2=n*(n-1)/2 for(int j=0;j<arr.length-1-i;j++){ compare++; if (arr[j]>arr[j+1]){ tmp=arr[j+1]; arr[j+1]=arr[j]; arr[j]=tmp; count++; } } } System.out.println(Arrays.toString(arr)); System.out.println("交换"+count+"次"); System.out.println(compare+"次比较"); } }
优化:添加退出点
遍历一遍如果没有发生交换表示序列已经有序,可以直接退出
/** * 优化;遍历一遍如果没有发生交换表示序列已经有序,可以退出 * @param arr * @author 夜神 */ public static void setBreakPointSort(int[] arr) { // 交换次数 int count=0; // 总共比较次数,也是最大交换次数(最坏情况:倒序) int compare=0; int tmp; // n-1轮 i 属于[0,n-1),即[0,n-2] for (int i=0;i<arr.length-1;i++){ //每轮遍历前,设置有序标识 boolean isSorted = true; // 每轮比较n-1-i次 总共(n-1)-0+(n-1)-1+(n-1)-2+....=(n-1)*(n-1)-(0+1+2+...+n-1-1)=(n-1)*(n-1)-(n-2)*(n-1)/2=n*(n-1)/2 for(int j=0;j<arr.length-1-i;j++){ compare++; if (arr[j]>arr[j+1]){ tmp=arr[j+1]; arr[j+1]=arr[j]; arr[j]=tmp; count++; isSorted = false; } } // 如果遍历一轮没有发生交换表示序列已经有序 if (isSorted) { break; } } System.out.println(Arrays.toString(arr)); System.out.println("交换"+count+"次"); System.out.println(compare+"次比较"); }
优化:有序区间界定
数组中可能有已经有序的区域,有序区域不需要再重新比较交换
每比较一轮,有序区域+1,但是实际有序区域可能更长(本身就有部分是有序的)
可以在每一轮排序后,记录下来最后一次元素交换的位置,该位置即为边界点,前面的是无序区域,后面的是有序区域
内层for循环比较完,通过中间值记录最后发生交换的位置(边界点),在外层for循环中更新边界点
/** * 区域优化法 * @param array */ public static void areaOptimizeSort(int[] array) { int tmp = 0; //记录最后一次交换的位置 int lastExchangeIndex = 0; //无序数列的边界,每次比较只需要比到这里为止 初始为数组末尾 int sortBorder = array.length - 1; //控制轮数 n-1轮 for(int i = 0; i < array.length-1; i++) { //有序标记,每一轮的初始是true 遍历一遍不发生变化说明已经有序 boolean isSorted = true; // 直接在无序区域内进行比较 for(int j = 0; j < sortBorder; j++) { // 发生交换 if(array[j] > array[j+1]) { tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; //有元素交换,所以不是有序,标记变为false isSorted = false; //把无序数列的边界更新为最后一次交换元素的位置 lastExchangeIndex = j; } } // 更新边界点位置:最后发生交换的位置 sortBorder = lastExchangeIndex; if(isSorted){ break; } } }
升级:鸡尾酒排序
作者: deity-night
出处: https://www.cnblogs.com/deity-night/
关于作者:码农
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(***@163.com)咨询.