1. 冒泡与选择排序及其比较

冒泡排序

1. 思想

  冒泡排序(Bubble Sort)是一种交换排序,基本思路是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止

 

2. 实现

2.1 初学常用的一种

public static <T extends Comparable<? super T>> void BubbleSort(T[] a) {
  int length = a.length;
  for (int i = 0; i < length; i++) {
    for (int j = i+1; j < length; j++) {
      if (a[i].compareTo(a[j]) > 0) {
        Object obj = a[i];
        a[j] = a[i];
        a[i] = (T)obj;
      } // end if
    } // end for
  } // end for
} // end BubbleSort

  缺陷:每一次内循环结束时,对其余的关键字没有帮助,甚至把原来靠近正确排序位置的记录交换到较远的地方。即,算法是低效的。

 

 

2.2 正宗的冒泡排序

public static <T extends Comparable<? super T>> void BubbleSort(T[] a) {
  int length = a.length;
  for (int i = 0; i < length - 1; i++) {
    for (int j = length - 2; j >= i; j--) {
      if (a[j].compareTo(a[j+1]) > 0) {
        Object obj = a[i];
        a[i] = a[j];
        a[j] = (T)obj;
      } // end if
    } // end for
  } // end for
} // end BubbleSort

  

  显然这一算法比之前的实现要有效,图中较小的数字如同气泡慢慢浮到上面,因此将此算法命名为冒泡排序。 

 

2.3 冒泡排序的优化

  对于已经有序或接近有序的集合时,会进行很多次不必要的循环比较,为此,需要改进实现,设置一个flag记录在一次循环比较中是否有交换操作,如果没有说明集合已经有序。

public static <T extends Comparable<? super T>> void BubbleSort(T[] a) {
  int length = a.length;
  boolean flag = true;  // 用flag作为标记
  for (int i = 0; (i < length - 1) && flag; i++) {
    flag = false;
    for (int j = length - 2; j >= i; j--) {
      if (a[j].compareTo(a[j+1]) > 0) {
        Object obj = a[i];
        a[i] = a[j];
        a[j] = (T)obj;
        flag = true;     // 有数据交换则为true
      } // end if
    } // end for
  } // end for
} // end BubbleSort

 

2.4 冒泡排序复杂度分析

  最好的情况下,也就是数组有序时,根据最后改进的代码,需要比较n-1次关键字,没有数据交换,时间复杂度为O(n)最坏的情况下,即待排序记录全为倒序,此时比较1+2+3+4+…+(n-1) = n(n-1)/2次,并作等数量级的记录移动。所以时间复杂度为O(n2)。

 

简单选择排序

1. 思想

  冒泡排序的思想就不断地在交换,通过交换完成最终的排序。这种方式太繁琐,可不可以在确定位置的时候在交换,减少交换操作,完成只交换一次就完成相应关键字的排序定位?这就是选择排序的初步思想。

 

2. 排序算法

  简单选择排序Simple Selection Sort)就是通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1 ≤ i ≤ n)个记录交换。

// simple selection sort
public static <T extends Comparable<? super T>> void SelectSort(T[] a) {
  int length = a.length;
  for (int i = 0; i < length - 1; i++) {
    int min = i;
    for (int j = i+1; j < length; j++) {
      if (a[min].compareTo(a[j]) > 0) {
        min = j;
      } // end if
    } // end for
    if (i != min) {
      Object obj = a[min];
      a[min] = a[i];
      a[i] = (T)obj;
    } // end if
  } // end for
} // end SelectSort

 

3. 简单选择排序复杂度分析

  从简单选择排序过程看,最大的特点是减少了移动数据的次数,这样节约了时间。无论最好还是最差的情况下,比较次数都是一样的,i趟要比较n-i次关键字,共需要比较(n-1)+(n-2)+…+2+1=n(n-1)/2次,最好情况下,即有序时,交换0次,最坏情况下,即逆序时,交换n-1次。最终排序时间为比较和移动的总和,时间复杂度为O(n2)。

尽管与冒泡排序同为O(n2),但简单选择排序的性能还是要略优于冒泡排序。(下列比较却不是!)

 

冒泡与选择排序对比

import java.util.Arrays;
/**
 * sort for Array
 * @author Administrator
 */
public class Sort {
  // 非标准的冒泡排序,最简单的交换排序!(让每一个关键字,都和它后面的每一个关键字比较,如果大则交换)
  public static void BubbleSort1(int[] a) {
    int length = a.length;
    for (int i = 0; i < length; i++) {
      for (int j = i+1; j < length; j++) {
        if (a[i] > a[j]) {
          int obj = a[i];
          a[i] = a[j];
          a[j] = obj;
        } // end if
      } // end for
    } // end for
  } // end BubbleSort

  //  标准冒泡排序
  public static void BubbleSort2(int[] a) {
    int length = a.length;
    for (int i = 0; i < length - 1; i++) {
      for (int j = length - 2; j >= i; j--) {
        if (a[j] > a[j+1]) {
          int obj = a[j];
          a[j] = a[j+1];
          a[j+1] = obj;
        } // end if
      } // end for
    } // end for
  } // end BubbleSort

  public static void BubbleSort3(int[] a) {
    int length = a.length;
    boolean flag = true;  // 用flag作为标记
    for (int i = 0; (i < length - 1) && flag; i++) {
      flag = false;
      for (int j = length - 2; j >= i; j--) {
        if (a[j] > a[j+1]) {
          int obj = a[j];
          a[j] = a[j+1];
          a[j+1] = obj;
          flag = true;     // 有数据交换则为true
        } // end if
      } // end for
     } // end for
  } // end BubbleSort

  // simple selection sort
  public static void SelectSort(int[] a) {
    int length = a.length;
    for (int i = 0; i < length - 1; i++) {
      int min = i;
      for (int j = i+1; j < length; j++) {
        if (a[min] > a[j]) {
          min = j;
        } // end if
      } // end for
      if (i != min) {
        int obj = a[min];
        a[min] = a[i];
        a[i] = obj;
      } // end if
    } // end for
  } // end SelectSort

  public static void main(String[] args) {
    // 随机生成50000、50_0000的整数
    int[] a = new int[50_0000];
    for (int i = 0; i < a.length; i++) {
      a[i] = (int)(Math.random() * 500);
      //System.out.print(a[i] + " ");
    }
    // System.out.println();
    // 保证各个排序算法使用的数据一样
    int[] a2 = Arrays.copyOf(a, a.length);
    int[] a3 = Arrays.copyOf(a, a.length);
    int[] a4 = Arrays.copyOf(a, a.length);
    Date d1
= new Date();     BubbleSort1(a); // 最常用的初学实现 50000:919,962,1032 500000:59425,60701,59811     System.out.println(new Date().getTime() - d1.getTime());     Date d2 = new Date();     BubbleSort2(a2); // 标准冒泡 50000:5332,5300,5957 500000:491104,480838,478621     System.out.println(new Date().getTime() - d2.getTime());     Date d3 = new Date();     BubbleSort3(a3); // 改进冒泡 50000: 5477,5648,5696 500000:526451,522458,503981     System.out.println(new Date().getTime() - d3.getTime());     Date d4 = new Date();     SelectSort(a4); // 50000: 1118,1256,1076 500000:107144,95680,94796     System.out.println(new Date().getTime() - d4.getTime());   } } // end Sort

  可以看出对于随机数组,常用的冒泡性能最好,接下来是简单选择排序,标准冒泡和改进的冒泡效率不如初学常用的冒泡高。改进的冒泡排序适合于接近有序或已经有序的情况。

posted @ 2018-09-27 21:33  dedication  阅读(1424)  评论(0编辑  收藏  举报