常见的排序算法
1. 冒泡排序
public interface Sort<T extends Comparable<T>> { public void sort(T[] array); }
/** * * 类名: MPSort.java * 类描述: 冒泡排序 * 备注: * <li>比较相邻的元素。如果第一个比第二个大,就交换他们两个。</li> * <li>对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。</li> * <li>针对所有的元素重复以上的步骤,除了最后一个。</li> * <li>持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。</li> */ public class MPSort<T extends Comparable<T>> implements Sort<T>{ @Override public void sort(T[] array) { if(null != array && array.length > 0){ for(int i=0; i<array.length-1; i++){ for(int j=i+1; j<array.length; j++){ if(array[i].compareTo(array[j])>0){ T temp = array[i]; array[i] = array[j]; array[j] = temp; } } } } } }
2. 选择排序
/** * * <pre> * 类名: XZSort.java * 类描述: 选择排序 * 备注: 选择排序,先将第一个数和后续的数依次比较,找到最大的(或最小的)数,然后把该数和第一个数位置交换,然后依次对后续的数循环做此处理。 * </pre> */ public class XZSort<T extends Comparable<T>> implements Sort<T>{ @Override public void sort(T[] array) { if(null != array && array.length > 0){ for(int i=0; i<array.length-1; i++){ int index = i; for(int j=i+1; j<array.length; j++){ if(array[index].compareTo(array[j]) > 0){ index = j; } } if(index != i){ T temp = array[i]; array[i] = array[index]; array[index] = temp; } } } } }
3. 插入排序
/** * * <pre> * 类名: CRSort.java * 类描述: 插入排序 * 备注:插入排序把要排序的数组分成两部分,第一部分包含这个数组的所有元素,最后一个元素除外,而第二部分只包含这一元素; * 在第一部分排序后,再把这个最后元素插入到此刻已经排好序的第一部分的正确位置。 * </pre> */ public class CRSort<T extends Comparable<T>> implements Sort<T> { @Override public void sort(T[] array) { if(null != array && array.length > 0){ for(int i = 1; i< array.length; i++){ for(int j = i; j > 0; j--){ if(array[j].compareTo(array[j-1]) < 0){ T temp = array[j-1]; array[j-1] = array[j]; array[j] = temp; } } } } } }
4. 快速排序
/** * <pre> * 类名: KSSort.java * 类描述: 快速排序 * 备注: * <li>从数列中挑出一个元素,称为“基准”</li> * <li>重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后, 该基准是它的最后位置。这个称为分割(partition)操作。</li> * <li>递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。</li> * </pre> */ public class KSSort<T extends Comparable<T>> { public void sort(T[] array, int start, int end) { int i=start; int j=end; T temp; T p = array[start]; do{ while(array[i].compareTo(p)<0 && i<end){ i++; } while(array[j].compareTo(p)>0 && j>start){ j--; } if(i<=j){ temp = array[i]; array[i] = array[j]; array[j] = temp; i++; j--; } }while(i<=j); if(start<j){ sort(array, start, j); } if(i<end){ sort(array, i, end); } } }
5. 归并排序(转自:http://blog.csdn.net/apei830/article/details/6591632)
/** * 项目名: sort * 类名: GBSort.java * 类描述: 归并排序 * 备注: 归并排序是把已经排好序的两个序列合并成一个有序序列 */ public class GBSort{ public static void mergeSort(Integer[] data) { sort(data, 0, data.length - 1); } public static void sort(Integer[] data, int left, int right) { if (left >= right) return; // 找出中间索引 int center = (left + right) / 2; // 对左边数组进行递归 sort(data, left, center); // 对右边数组进行递归 sort(data, center + 1, right); // 合并 merge(data, left, center, right); } /** * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 * * @param data * 数组对象 * @param left * 左数组的第一个元素的索引 * @param center * 左数组的最后一个元素的索引,center+1是右数组第一个元素的索引 * @param right * 右数组最后一个元素的索引 */ public static void merge(Integer[] data, int left, int center, int right) { // 临时数组 int[] tmpArr = new int[data.length]; // 右数组第一个元素索引 int mid = center + 1; // third 记录临时数组的索引 int third = left; // 缓存左数组第一个元素的索引 int tmp = left; while (left <= center && mid <= right) { // 从两个数组中取出最小的放入临时数组 if (data[left] <= data[mid]) { tmpArr[third++] = data[left++]; } else { tmpArr[third++] = data[mid++]; } } // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个) while (mid <= right) { tmpArr[third++] = data[mid++]; } while (left <= center) { tmpArr[third++] = data[left++]; } // 将临时数组中的内容拷贝回原数组中 // (原left-right范围的内容被复制回原数组) while (tmp <= right) { data[tmp] = tmpArr[tmp++]; } } }
这几种排序的效率比较:
public class Test { static Random random = new Random(System.nanoTime()); public static Integer[] getIngegerArray(int count){ Integer[] array = new Integer[count]; for(int i=0; i<count; i++){ array[i] = random.nextInt(count)+1; } return array; } public static void main(String[] args) { int count = 100000; Integer[] array = getIngegerArray(count); Integer[] array1 = new Integer[count]; System.arraycopy(array, 0, array1, 0, count); Integer[] array2 = new Integer[count]; System.arraycopy(array, 0, array2, 0, count); Integer[] array3 = new Integer[count]; System.arraycopy(array, 0, array3, 0, count); Integer[] array4 = new Integer[count]; System.arraycopy(array, 0, array4, 0, count); KSSort ksSort = new KSSort(); long time1 = System.nanoTime(); ksSort.sort(array1, 0, count-1); long time2 = System.nanoTime(); System.out.println("快速排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms"); Sort crSort = new CRSort<>(); time1 = System.nanoTime(); crSort.sort(array2); time2 = System.nanoTime(); System.out.println("插入排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms"); Sort mpSort = new MPSort<>(); time1 = System.nanoTime(); mpSort.sort(array3); time2 = System.nanoTime(); System.out.println("冒泡排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms"); Sort xzSort = new XZSort<>(); time1 = System.nanoTime(); xzSort.sort(array); time2 = System.nanoTime(); System.out.println("选择排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms");
<span style="white-space:pre"> </span>GBSort gbSort = new GBSort(); <span style="white-space:pre"> </span>time1 = System.nanoTime(); <span style="white-space:pre"> </span>gbSort.mergeSort(array6); <span style="white-space:pre"> </span>time2 = System.nanoTime(); <span style="white-space:pre"> </span>System.out.println("归并排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms"); } }
快速排序:排10000个整数耗时:3ms 插入排序:排10000个整数耗时:681ms 冒泡排序:排10000个整数耗时:747ms 选择排序:排10000个整数耗时:486ms
测试结果2:
快速排序:排1000个整数耗时:2ms 插入排序:排1000个整数耗时:7ms 冒泡排序:排1000个整数耗时:7ms 选择排序:排1000个整数耗时:5ms
测试结果3:
快速排序:排50000个整数耗时:20ms 插入排序:排50000个整数耗时:19009ms 冒泡排序:排50000个整数耗时:27390ms 选择排序:排50000个整数耗时:15217ms
测试结果4:
快速排序:排10000个整数耗时:3ms 插入排序:排10000个整数耗时:590ms 冒泡排序:排10000个整数耗时:665ms 选择排序:排10000个整数耗时:400ms 数组自带Api排序:排10000个整数耗时:5ms 归并排序:排10000个整数耗时:265ms
另外,再加上一个数组自带的排序方法:
time1 = System.nanoTime(); Arrays.sort(array5); time2 = System.nanoTime(); System.out.println("数组自带Api排序:排"+count+"个整数耗时:"+(time2-time1)/1000000+"ms");
输出结果:
数组自带Api排序:排50000个整数耗时:21ms