交换排序—冒泡排序(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;
  }
}

相邻值相同时不交换情况下,可以保持稳定性。

你可能感兴趣的:(交换排序—冒泡排序(Bubble Sort))