u07-数组排序

168 阅读4分钟

1. 选择排序 SelectionSort

概念:

  • 选择排序是一种简单直观的排序算法,它的工作原理是每一次从无序区中选出最小(或最大)的一个元素,追加到有序区,直到全部无序区的数据元素排完。
  • 选择排序是不稳定的排序方法,比如序列 [5, 5, 3] 第一轮就将第一个 53 交换,导致第一个 5 挪动到第二个 5 后面。
  • 选择排序的核心思想是抢夺:从第一个数开始,依次和后面所有的数进行比较。

流程: 以正序为例:{1, 3, 154, 2345, 1345}

  1. arrs[0] 和后面所有的元素比较,发现小的就抢过来:
    • 第1轮下来,arrs[0] 位置上就是整个数组中第1小的元素。
    • arrs[0] 组成有序区,其余仍在无序区。
  2. arrs[1] 和后面所有的元素比较,发现小的就抢过来:
    • 第2轮下来,arrs[1] 位置上就是整个数组中第2小的元素。
    • arrs[0]arrs[1] 组成有序区,其余仍在无序区。
  3. arrs[2] 和后面所有的元素比较,发现小的就抢过来:
    • 第3轮下来,arrs[2] 位置上就是整个数组中第3小的元素。
    • arrs[0]arrs[1]arrs[2] 组成有序区,其余仍在无序区。
  4. ...
  5. 一共比较length-1次,无序区没有任何元素了,只剩下有序区,数组就排好序了。

源码: /javase-start/

  • src: c.y.arraysort.SelectionSortTest
/**
 * @author yap
 */
public class SelectionSortTest {
    @Test
    public void selectionSort(){
        int[] arr = { 101, 2, 23, 133, 412, 23, 412, 51, 235 };

        // 每轮都将确定将一个无序区中最小的元素追加到有序区,需要比较N-1次
        for (int i = 0, j = arr.length - 1; i < j; i++) {

            // 每一次都拿一个元素和后面所有的元素进行比较
            for (int m = i + 1, n = arr.length; m < n; m++) {

                // 只要比arr[x]小,arr[x]就将其抢夺,最终arr[x]一定是无序区最小的元素
                if (arr[i] < arr[m]) {
                    int temp = arr[i];
                    arr[i] = arr[m];
                    arr[m] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

2. 冒泡排序 BubbleSort

概念:

  • 冒泡排序是一种计算机科学领域的较简单的排序算法,它从头开始,不断地比较相邻的两个元素,并进行对应的交换,直到最后排序完成。
  • 这个算法的名字由来是因为越大(越小)的元素会经由交换慢慢浮到数列的顶端,故名。
  • 冒泡排序的核心思想是交换:相邻的两个数进行比较。

流程: 以正序为例:{3, 1, 4, 2, 5};

  1. 比较相邻的元素,如果前数比后数大,就交换他们两个。
  2. 每一轮的工作内容是:对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。
  3. 1轮结束后,数组倒数第1位的元素一定是数组中第1大的数,5个数需要比4次。
  4. 2轮结束后,数组倒数第2位的元素一定是数组中第2大的数,需要比3次。
  5. 3轮结束后,数组倒数第3位的元素一定是数组中第3大的数,需要比2次。
  6. ...
  7. 一共要比较4轮(n-1轮)。

源码: /javase-start/

  • src: c.y.arraysort.BubbleSortTest
/**
 * @author yap
 */
public class BubbleSortTest {
    @Test
    public void bubbleSort(){
        int[] arr = { 101, 2, 23, 133, 412, 23, 412, 51, 235 };

        // 每一轮:9个数,两两相比,要比9-1轮
        for (int i = 0, j = arr.length - 1; i < j; i++) {

            // 相邻两个数比较,需要比较length-1-i次
            for (int m = 0, n = arr.length - 1 - i; m < n; m++) {

                // 前数大于后数就交换,循环一次完毕保证最大的数排最后
                if (arr[m] > arr[m + 1]) {
                    int temp = arr[m];
                    arr[m] = arr[m + 1];
                    arr[m + 1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

3. 插入排序 InsertSort

概念:

  • 有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法,插入排序法。
  • 插入排序就是我们生活中按大小个排序的基本排序思想,基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,是稳定的排序方法。
  • 原理就是从第二个元素开始,每次都和前一位的元素进行比较,如果小于前面的元素,则交换位置,继续向前比较,直到该元素排到第一位或者不再小于前面的元素,如果不小于前面的元素,则直接继续操作下一个元素。
  • 插入排序的核心思想是插队:从第二个数开始,依次和前面的数进行比较。

流程: 我们这里以正序为例:{3, 1, 4, 2, 5};(个头小的往前站)

  1. 我们假定 [3] 是一个排好序的队伍,从第二个元素开始每个元素看做一个新的,想要插队的元素。
  2. 第二个元素是 11 要插队,跟队尾的 3 比较,赢了,和 3 交换位置,得到一个新的队伍 [1, 3]
  3. 第三个元素是 44 要插队,先跟队尾的 3 比较,输了,不动,得到一个新的队伍 [1, 3, 4]
  4. 第四个元素是 22 要插队,先跟队尾的 4 比较,赢了,和 4 交换,得到一个新的队伍 [1, 3, 2, 4]
    • 再和 3 比较,赢了,和 3 交换,得到新的队伍 [1, 2, 3, 4]
    • 再和 1 比较,输了,不动,最终得到数组 [1, 2, 3, 4]
  5. 第五个元素是 55 要插队,先跟队尾的 4 比较,输了,结束。
  6. 最终队伍 [1, 2, 3, 4, 5]

源码: /javase-start/

  • src: c.y.arraysort.InsertSortTest

/**
 * @author yap
 */
public class InsertSortTest {
    @Test
    public void insertSort() {
        int[] arr = {101, 2, 23, 133, 412, 23, 412, 51, 235};

        // 从第i个位置开始依次向前比较,i从1开始,因为第0个人无法和它前面的人进行比较
        // 由于你的i是从1开始的,所以判断条件要改为i<arrs.length,不能使用length-1,否则会少比一次
        for (int i = 1, j = arr.length; i < j; i++) {

            // 角标为1的人(第二个人),最多需要向前比较1次
            // 角标为2的人(第三个人),最多需要向前比较2次
            // 角标为i的人(第i+1个人),最多需要向前比较i次,所以m = i ; m > 0 ; m--
            for (int m = i; m > 0; m--) {

                // 若后面的数小,交换,若后面的数大,直接结束循环,没有再向前比较的必要
                if (arr[m] < arr[m - 1]) {
                    int temp = arr[m];
                    arr[m] = arr[m - 1];
                    arr[m - 1] = temp;
                } else {
                    break;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}