常见的几种排序方法
冒泡排序
原理:进行多次比较,每次比较都将较大的元素放置在后面,这样,一趟排序下来,就可以找到最大的数放置在数组的最后。
代码:
package sort; /** * 冒泡排序:普通方法、优化、递归 * 原理:当前元素和下一个元素进行比较,将较大的元素放置到后面, * 这样一趟比较下来,就将最大的值放置到待排序的数组底端 * * 时间复杂度:n^2 * @author Administrator * @date 2018-6-4 */ public class MaoPao { public static void main(String[] args) { int a[] = {5, 7, 8, 4, 3, 9}; int b[] = {5, 7, 8, 4, 3, 9}; int c[] = {5, 7, 8, 4, 3, 9}; a = maoPao(a); b = maoPaoYouHua(b); c = maoPaoDiGui(c, 0); } private static int[] maoPao(int[] data){ int num = 0; //外层循环是,排序的趟数 for(int i = 0; i < data.length - 1; i++){ //内层循环是,当前趟数需要比较的次数 for(int j = 0; j < data.length - 1; j++){ // 如果当前元素比后一个元素大,交换位置 if(data[j] > data[j + 1]){ int temp = data[j + 1]; data[j + 1] = data[j]; data[j] = temp; } } num++; } System.out.println("当前排序数组的名称:a, 比较的趟数:" + num); for(int bb : data){ System.out.print(bb + " "); } System.out.println(); return data; } private static int[] maoPaoYouHua(int[] data){ int num = 0;//比较的趟数 for(int i = 0; i < data.length - 1; i++){ int isChange = 0;//0表示没有替换过,1表示替换过 for(int j = 0; j < data.length - 1; j++){ if(data[j] > data[j + 1]){ int temp = data[j + 1]; data[j + 1] = data[j]; data[j] = temp; isChange = 1; } } if(isChange == 0){ break; } num++; } System.out.println("当前排序数组的名称:b, 比较的趟数:" + num); for(int bb : data){ System.out.print(bb + " "); } System.out.println(); return data; } /** * 递归+优化后的冒泡排序 * @param data * @param ts 比较的第几趟 * @return */ private static int[] maoPaoDiGui(int[] data, int ts){ //最多比较data.length-1次 if(ts >= data.length - 1){ System.out.println("当前排序数组的名称:c, 比较的趟数:" + ts); for(int bb : data){ System.out.print(bb + " "); } return data; } int isChange = 0; //真正比较的地方 for(int i = 0; i < data.length - 1; i++){ if(data[i] > data[i + 1]){ int temp = data[i + 1]; data[i + 1] = data[i]; data[i] = temp; isChange = 1; } } if(isChange == 0){ System.out.println("当前排序数组的名称:c, 比较的趟数:" + ts); for(int bb : data){ System.out.print(bb + " "); } return data; } //ts + 1 表示比较的趟数 + 1 return maoPaoDiGui(data, ts + 1); } }
插入排序
原理:取待的其中一个,和已经排序好的序列比较,并且插入到其中,二分法排序是插入排序的一种优化。
代码特点: 1.取待排序的数组的第一位作为已经排好序的序列; 2.从第二个元素开始比较
代码:
package sort; /** * 插入排序: * 原理: 取待排序的数组第一位元素作为已经排序好的数组,将第二位元素与之比较,大位置不变,小则交换位置; * 将第三位元素与之间排序好的1、2位数组,进行比较排序,以此类推。 * 时间复杂度:n^2 * @author zhuwei * */ public class ChaRu { public static void main(String[] args) { int a[] = {5, 2, 1, 4, 9}; int b[] = {5, 2, 1, 4, 9}; a = chaRu(a); b = chrRuBinary(b); } private static int[] chaRu(int[] a){ // 从第二个元素开始比较 for(int i = 1; i < a.length - 1; i++){ int temp = a[i];//记录待排序的元素 // 如果比前一个元素小,进行循环比较并交换位置; // j > 0条件是表示如果待排序元素比前面排序好的所有元素都小,j-1下标小于0的情况 int j = i; while(j > 0 && a[j - 1] > temp){ a[j] = a[j - 1]; j--;//向前移动 } a[j] = temp; } for(int b : a){ System.out.print(b + " "); } return a; } private static int[] chrRuBinary(int[] a){ int temp; for(int i = 1; i < a.length; i++){ temp = a[i]; //使用二分法查找出插入的位置 int index = binary(a, i, temp); System.out.println(temp + " 插入位置:" + index); //根据插入位置后移元素 for(int j = i; j > index; j--){ a[j] = a[j - 1]; } a[index] = temp; for(int b : a){ System.out.print(b + " "); } System.out.println(); } for(int b : a){ System.out.print(b + " "); } return a; } /** * 根据二分法查找应该插入的位置 * @param array * @param end 已经排序好的序列的下标 * @param data 待插入元素 * @return */ private static int binary(int[] array, int end, int data){ int start = 0; int mid = -1; //一定要添加“=”,因为当带插入的元素比mid上的元素小,但是比mid-1大时,等于可以让元素放在两者之间 while(start <= end && start < array.length - 1){ mid = (start + end) / 2; if(array[mid] > data){ end = mid - 1; }else{ start = mid + 1; } } return start; } }
选择排序
原理:选择待排序的数组中最大(最小)放置在数组的最后(最前)的位置,直到排序完成。
代码特点:第二层循环条件为:array.length - i,因为后面排序好的不需要再进行比较
代码:
package sort; /** * 选择排序: * 原理:每一趟比较都选出一个最大或者最小的放置在数组的最前或者最后端 * * 时间复杂度:n^2 * @author Administrator * @date 2018-6-4 */ public class XuanZe { public static void main(String[] args) { int[] a = {2, 1, 3, 4, 3, 9, 8, 7, 6}; a = xuanZe(a); } /** * 选择排序是不稳定的,比较之后,相同的两个元素前后位置顺序发生变化 * @param data * @return */ private static int[] xuanZe(int[] data){ int des = 0; //比较的趟数 for(int i = 0; i < data.length - 1; i++){ des = 0; //注意这里和冒泡排序不同是data.length-i,不是-1,因为冒泡如果是 //是-i的话,当i = 0时,下面的i+1会超出数组下标,并且-1,会比较后面已经排序好的元素,对于冒泡来说 //是不会发生元素交换的,所以没有影响,但是选择因为不会取到最后一个元素,会导致元素交换,所以选择排序 //是-i,后面排序好的元素,不需要再比较 for(int j = 0; j < data.length - i; j++){ if(data[j] > data[des]){ des = j; } } int temp = data[des];//一趟比较下来的最大数,进行交换 data[des] = data[data.length - 1 - i];//将大的元素依次放入数组后面 data[data.length - 1 - i] = temp; System.out.println(i + ":"); for(int b : data){ System.out.print(b + " "); } System.out.println(); } return data; } }
快速排序
原理:在待排序数组中取一个元素作为基础,依次和数组中的元素比较,比基数大的放在基数的右边,比基数小的放在基数的左边。
代码特点:1.基数一般选择数组的第一位; 2.利用递归,递归结束条件start < end
代码:
package sort; import java.util.Arrays; /** * 原理:在待排序数组中取一个元素作为基础,依次和数组中的元素比较,比基数大的放在基数的右边,比基数小的放在基数的左边。 * 时间复杂度:nlogn * @author Administrator * */ public class QuickSort { public static void main(String args[]) { QuickSort quicksort = new QuickSort(); int[] a = {1, 2, 3, 4, 5, 6, }; quicksort.quickSort(a); System.out.println(Arrays.toString(a)); } private void quickSort(int[] arrays) { subQuickSort(arrays, 0, arrays.length - 1); } private void subQuickSort(int[] arrays, int start, int end) { if (start >= end) { return; } int middleIndex = subQuickSortCore(arrays, start, end); // 递归排序基数左边的数组 subQuickSort(arrays, start, middleIndex - 1); // 递归排序基数右边的数组 subQuickSort(arrays, middleIndex + 1, end); } private int subQuickSortCore(int[] arrays, int start, int end) { // 找到基数,start 为0时,以第一位作为基数 int middleValue = arrays[start]; while (start < end) {// 结束递归的条件 // 从后往前找到比基数小的数的下标 while (arrays[end] >= middleValue && start < end) { end--; } // 将基数位置值赋值成找到的比基础小的数,这时数组中出现2个此数 arrays[start] = arrays[end]; // 从前往后找到比基础大的数的下标 while (arrays[start] <= middleValue && start < end) { start++; } // 将较大的数赋值到原来较小数的位置上,此时数组中出现2个较大的数 arrays[end] = arrays[start]; } // 将原来较大的数的位置上赋值成基数 arrays[start] = middleValue; // 最后返回基数的位置 return start; } }