欢迎Java爱好者品读其他算法详解:
简单比较排序:http://blog.csdn.net/ysjian_pingcx/article/details/8652091
冒泡排序: http://blog.csdn.net/ysjian_pingcx/article/details/8653732
直接插入排序:http://blog.csdn.net/ysjian_pingcx/article/details/8674454
快速排序: http://blog.csdn.net/ysjian_pingcx/article/details/8687444
快速排序优化:http://blog.csdn.net/ysjian_pingcx/article/details/8687444
选择排序<详解+优化>
前面介绍了入门的算法比较排序,还有形象的的冒泡排序。不过说出来很伤心,这种排序法效率是很低的,比较排序中需要用一个元素与后面的每一个元素进行比较,如果发现有反序的就交换,这样的话效率是很低的,所以这里引入一个选择排序,与比较排序相似,只不过,在每一趟排序中,比较过程中发现反序的时候,并没有及时交换两个数据,而是引入了一个假设的最小值的下标标记,将这个标记赋值为当前比较中最小记录对应的下标,一直到一趟下来,将所有的记录比较完毕,最后交换两个下标对应的记录,用了比较排序的思路,但是抛弃了每一次交换两个记录的步骤。
选择排序思路:
一趟在 n - i + 1(n = 1,2,3...,n - 1)个记录中选取关键字最小的记录作为有序序列的第i个记录。
关键点:比较两个记录的大小,如果反序,记录下下标,知道一趟比较完毕,让后将原来第i个记录与最后记录的小标的记录交换。
看看下面一趟排序的过程分析图:
核心的比较交换代码:
/** * 选择排序算法的核心程序 * @param array */ public void selectSort(int... array){ int length = array.length; for (int i = 0; i < length - 1; i++) { int min = i; // 将当前下标定义为最小值得下标,然后与后面的值一一比较 for (int j = i + 1; j < length; j++) { if (array[min] > array[j]) { min = j; // 如果有比假设的值更小的,就将这个值的下标给min,没有重复的交换 } } if (min != i) { // 如果最小值的下标有变动,就将一轮比较后的最小值与与开始的值交换 swap(i, min, array); } } }@int min = i;这个条件,已进入循环,将当前 i 赋给 min,然后将 i 对应的记录与后面多有的元素进行比较,如果有反序的,就将 j 赋给 min;
@内部循环完毕,也就是一趟比较完毕,if(min != i),如果有变动,就交换最终那个下标与 i 对应的记录,也就是,将最小值交换到第 i 个;
@swap是交换数组两个元素的方法,这里不再赘述;
与冒泡排序相似,如果我们待排序的有序序列一开始是有序的,那么第一次比较之后,发现都是正序,那么后面的比较是不是多余的呢,这种多余我们是不是可以认为控制一下呢?答案是肯定的呢?
选择排序算法核心程序的优化:
/** * 优化的排序算法的核心程序 * @param array */ public void selectSort(int... array){ int length = array.length; boolean flag = true;// 配置一个标记,用于对已经有序的数组排序时的简化后面的比较操作 for (int i = 0; i < length - 1 && flag; i++) { // 作为进入循环的条件 flag = false; // 进来之后就置为false int min = i; // 将当前下标定义为最小值得下标,然后与后面的值意义比较 for (int j = i + 1; j < length; j++) { if (array[min] > array[j]) { flag = true; //如果有交换,就置为true min = j; // 如果有比假设的值更小的,就将这个值的下标给min,没有重复的交换 } } if (flag) { // 如果最小值的下标有变动,就将一轮比较后的最小值与与开始的值交换 swap(i, min, array); } } }@多了一个boolean flag = true;一个标记,作为外部循环的条件之一;
@进入了外部循环,将 flag = false; 这个思路是假设序列是有序的;
@在内部比较的过程中,if(array[min] > array[j])成立,就是有反序的,就将flag = true;说明序列不是有序的;
选择排序也是一种常见的简单的排序,很容易理解,那么这里就不多说了,下面提供完整的代码(优化后的):
/** * 优化选择排序算法 * @author PingCX * */ public class SelectSortOpt { public static void main(String[] args) { SelectSortOpt selectSort = new SelectSortOpt(); int[] array = { 25, 36, 21, 45, 98, 13}; System.out.println(Arrays.toString(array)); selectSort.selectSort(array); System.out.println(Arrays.toString(array)); } /** * 优化的排序算法的核心程序 * @param array */ public void selectSort(int... array){ int length = array.length; boolean flag = true;// 配置一个标记,用于对已经有序的数组排序时的简化后面的比较操作 for (int i = 0; i < length - 1 && flag; i++) { // 作为进入循环的条件 flag = false; // 进来之后就置为false int min = i; // 将当前下标定义为最小值得下标,然后与后面的值意义比较 for (int j = i + 1; j < length; j++) { if (array[min] > array[j]) { flag = true; //如果有交换,就置为true min = j; // 如果有比假设的值更小的,就将这个值的下标给min,没有重复的交换 } } if (flag) { // 如果最小值的下标有变动,就将一轮比较后的最小值与与开始的值交换 swap(i, min, array); } } } /** * 内部实现,用于交换数组的两个引用值 * * @param beforeIndex * @param afterIndex * @param arr */ private void swap(int oneIndex, int anotherIndex, int[] array) { int temp = array[oneIndex]; array[oneIndex] = array[anotherIndex]; array[anotherIndex] = temp; } }
和之前一样,在面向对象语言中,任何可以比较的类型,都可以拿来排序,在Java中是实现了Comparable接口的类:
/** * 任意可以比较类型的选择排序算法 * @author PingCX * */ public class SelectSortTOpt { public static void main(String[] args) { SelectSortTOpt selectSort = new SelectSortTOpt(); Integer[] array = { 25, 36, 21, 45, 98, 13}; System.out.println(Arrays.toString(array)); selectSort.selectSort(array); System.out.println(Arrays.toString(array)); } /** * 选择排序算法的核心程序 * @param array */ public <T extends Comparable<T>> void selectSort(T[] array){ int length = array.length; boolean flag = true; for (int i = 0; i < length - 1 && flag; i++) { flag = false; int min = i; // 将当前下标定义为最小值得下标,然后与后面的值意义比较 for (int j = i + 1; j < length; j++) { if (array[min].compareTo(array[j]) > 0) { flag = true; min = j; // 如果有比假设的值更小的,就将这个值的下标给min,没有重复的交换 } } if (flag) { // 如果最小值的下标有变动,就将一轮比较后的最小值与与开始的值交换 swap(i, min, array); } } } /** * 内部实现,用于交换数组的两个引用值 * * @param beforeIndex * @param afterIndex * @param arr */ private <T extends Comparable<T>> void swap(int oneIndex, int anotherIndex, T[] array) { T temp = array[oneIndex]; array[oneIndex] = array[anotherIndex]; array[anotherIndex] = temp; } }@在JDK中Integer类型是实现了Comparable接口的,所以可以作为列子;
@也可以自定义一个类,实现Comparable接口,重写了compareTo方法;
小结:选择排序法,没有突破时间复杂度为O(n²)的瓶颈,但是性能上略优于冒泡排序法,后面会写直接插入排序法,和一些高级排序算法,如希尔排序算法和快速排序算法。
尾声:人生就是一个不断选择的过程,态度胜过能力,选择同样胜过能力,在人生的十字路口上,做出一个选择,尤为重要,正确地认识一下,选择自己的想要的生活,少些计较,人生会更快乐...
欢迎Java爱好者品读其他算法详解:
简单比较排序:http://blog.csdn.net/ysjian_pingcx/article/details/8652091
冒泡排序: http://blog.csdn.net/ysjian_pingcx/article/details/8653732
直接插入排序:http://blog.csdn.net/ysjian_pingcx/article/details/8674454
快速排序: http://blog.csdn.net/ysjian_pingcx/article/details/8687444
快速排序优化:http://blog.csdn.net/ysjian_pingcx/article/details/8687444