计算机知识大讲堂

08.排序:冒泡,插入,选择

2020-05-24  本文已影响0人  学海一乌鸦

1.如何分析一个排序算法

1.排序算法的执行效率

2.冒泡排序(Bubble Sort)

image.png
public void bubbleSort(int[] arr) {
        if (arr == null || arr.length <= 0) {
            return;
        }
        int len = arr.length;
        // 提前退出循环的标志
        boolean flag = true;
        // 外层循序:一共进行几次循环,len-1
        // 内层循环:每次循环需要几次比较,因为靠后的数字已经比较完了,不需要再次比较,直接跳过就可以
        for (int i = 0; i < len - 1; i++) {
            for (int j = 0; j < len - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                    flag = false;
                }
            }
            // 没有数据交换,直接结束
            if (flag) {
                break;
            }
        }
    }
    private void swap(int[] arr, int m, int n) {
        if (arr == null || arr.length <= 0) {
            return;
        }
        if (m > arr.length - 1 || n > arr.length - 1) {
            return;
        }
        int tmp = arr[m];
        arr[m] = arr[n];
        arr[n] = tmp;
    }

自问自答:

最坏情况下,初始状态的有序度是 0,所以要进行 n(n-1)/2 次交换。最好情况下,初始状态的有序度是 n(n-1)/2,就不需要进行交换。我们可以取个中间值 n(n-1)/4,来表示初始有序度既不是很高也不是很低的平均情况。换句话说,平均情况下,需要 n(n-1)/4 次交换操作,比较操作肯定要比交换操作多,而复杂度的上限是 O(n2),所以平均情况下的时间复杂度就是 O(n2)。

3.插入排序

image.png

大体思想:将排序的数组分为已排序区域待排序区域,然后每次从待排序区域里面选择一个元素进行与已排序区域的元素进行比较,这里比较的方式是从尾到头比较,如果待比较的值小于已排序的元素,则进行搬移,否则中断流程;同时注意临界情况的处理;

 public void insertSort(int[] arr) {
        if (arr == null || arr.length <= 0) {
            return;
        }
        // 数组长度
        int n = arr.length;
        // 外层循环:定义已排序区域和未排序区域,默认第一个元素已经排序,故i从1开始
        for (int i = 1; i < n; i++) {
            // 待插入的元素,比较的元素从【0,i-1]
            int value = arr[i];
            int j = i - 1;
            // 内层循环,比较的元素从[i-1,0]倒序比较,符合的话break本次循环,不符合的话移动
            for (; j >= 0; j--) {
                if (arr[j] > value) {
                    // 为啥是j+1,因为在初始时,j+1=i,需要移动到这个位置,后面会依次有个空
                    arr[j + 1] = arr[j];
                } else {
                    break;
                }
            }
            // 空的位置是j+1
            arr[j + 1] = value;
        }
    }

冒泡排序中数据的交换操作:
if (a[j] > a[j+1]) { // 交换
   int tmp = a[j];
   a[j] = a[j+1];
   a[j+1] = tmp;
   flag = true;
}

插入排序中数据的移动操作:
if (a[j] > value) {
  a[j+1] = a[j];  // 数据移动
} else {
  break;
}

把执行一个赋值语句的时间粗略地计为单位时间(unit_time),然后分别用冒泡排序和插入排序对同一个逆序度是 K 的数组进行排序。用冒泡排序,需要 K 次交换操作,每次需要 3 个赋值语句,所以交换操作总耗时就是 3*K 单位时间。而插入排序中数据移动操作只需要 K 个单位时间。

选择排序

image.png

小结

image.png
上一篇 下一篇

猜你喜欢

热点阅读