交换排序—冒泡排序(Bubble Sort)
1 思想
待排序的一组数中,对当前还未排序的范围内的全部数,自上而下对相邻两数依次进行:
- 比较
 - 调整
 
让较大数往下沉,较小往上冒,故名冒泡排序。
即每当两相邻的数比较后,发现它们的排序与排序要求相反时,就互换。
  
2 实现
package com.sss;
import java.util.Arrays;
/**
 * @author JavaEdge
 */
public class BubbleSort {
  public static void bubbleSort(int[] arr) {
    if (arr == null || arr.length < 2) {
      return;
    }
    for (int e = arr.length - 1; e > 0; e--) {
      for (int i = 0; i < e; i++) {
        if (arr[i] > arr[i + 1]) {
          swap(arr, i, i + 1);
        }
      }
    }
  }
  public static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
  }
  // for test
  public static void comparator(int[] arr) {
    Arrays.sort(arr);
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static int[] copyArray(int[] arr) {
    if (arr == null) {
      return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
    }
    return res;
  }
  // for test
  public static boolean isEqual(int[] arr1, int[] arr2) {
    if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
    }
    if (arr1 == null && arr2 == null) {
      return true;
    }
    if (arr1.length != arr2.length) {
      return false;
    }
    for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
        return false;
      }
    }
    return true;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  // for test
  public static void main(String[] args) {
    int testTime = 500000;
    int maxSize = 100;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      bubbleSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
        succeed = false;
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    int[] arr = generateRandomArray(maxSize, maxValue);
    printArray(arr);
    bubbleSort(arr);
    printArray(arr);
  }
}3 改进
3.1 标志变量flag
标志某趟排序过程中,是否有数据交换。若某趟排序时并无数据交换,则说明数据已排好,可提前结束排序,避免后续多余的比较过程。
private void bubbleSort1(int[] arr) {
  int length = arr.length;
  boolean flag;
  for (int i = 0; i < length - 1; i++) {
    exchange = false;
    for (int j = 0; j < length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        flag = true;
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
    // 若本次循环无任何数据交换,则跳出循环
    if (!flag) {
      break;
    }
  }
}3.2 标志变量pos
记录每趟排序中最后一次进行交换的位置。
由于pos位置后的记录均已排序到位,所以执行下一趟排序时,只要扫描到pos位置即可!
void bubbleSort2(int[] arr) {
  int length = arr.length;
  // 初始时,最后位置保持不变
  int i = length - 1;
  while (i > 0) {
    // 每趟开始时,无记录交换
    int pos = 0;
    for (int j = 0; j < i; j++) {
      if (arr[j] > arr[j + 1]) {
        // 记录交换的位置
        pos = j;
        int tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
    // 为下一趟排序作准备
    i = pos;
  }
}3.3 正向和反向两遍冒泡
传统冒泡排序中每一趟排序操作只能找到一个max或min,考虑利用在每趟排序中进行正向和反向两遍冒泡的方法,一次便可得到max和min , 从而使排序趟数几乎减少一半。
void bubbleSort3(int[] arr) {
  int length = arr.length;
  // 设置变量初始值
  int low = 0;
  int high = length - 1;
  int tmp, j;
  while (low < high) {
    // 正向冒泡,找到max
    for (j = low; j < high; ++j) {
      if (arr[j] > arr[j + 1]) {
        tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = tmp;
      }
    }
    // 修改high值, 前移一位
    --high;
    // 反向冒泡,找到min
    for (j = high; j > low; --j) {
      if (arr[j] < arr[j - 1]) {
        tmp = arr[j];
        arr[j] = arr[j - 1];
        arr[j - 1] = tmp;
      }
    }
    // 修改low值,后移一位
    ++low;
  }
}相邻值相同时不交换情况下,可以保持稳定性。










