冒泡、插入、选择排序

(极客时间专栏 “数据结构与算法之美” 的学习笔记)

冒泡排序

冒泡排序只会操作相邻的两个数据。比较,交换之后,每一次冒泡之后会让至少一个元素移动到正确的位置。

public static void bubbleSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    for (int i = 0; i < arr.length; i++) {
        boolean flag = false;
        for (int j = 0; j < arr.length-i-1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1);
                flag = true;
            }
        }
        if (!flag) {
            return;
        }
    }
}

插入排序

取未排序区间中的首位元素,移动数据的同时,在已排序区间中找到合适的位置插入,并保证已排区间的数据一直有序,重复直到未排序部分为空。

简单总结过程

  • 外层循环遍历 1 to n
  • 内层循环后移数据, 插入 arr[i]
public static void insertSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    for (int i = 1; i < arr.length; i++) {
        int j = i - 1;
        int value = arr[i];
        for (; j >= 0; j--) {
            if (arr[j] > value) {
                arr[j + 1] = arr[j];
            } else {
                break;
            }
        }
        //已找到插入位置
        arr[j + 1] = value;
    }
}

选择排序

每次从未排序区间中找到最小值,放到已排序区间的末尾

public static void selectSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    for (int i = 0; i < arr.length; i++) {
        int min = i;
        for (int j = i + 1; j < arr.length; j++) {
            min = arr[j] < arr[min] ? j : min;
        }
        //将最小值放到已排区间的末尾
        if (min != i) {
            swap(arr, i, min);
        }
    }
}

总结

空间O(1) 是否稳定 最好 最坏 平均
冒泡 Y Y O(n) O(n^2) O(n^2)
插入 Y Y O(n) O(n^2) O(n^2)
选择 Y N O(n^2) O(n^2) O(n^2)

为什么插入排序比冒泡排序更好?
应用下面的程序测试,随机生成20个1w大小的数组来排序:
冒泡排序的运行时间是 2714 毫秒,插入排序的运行时间是 286 毫秒

冒泡比选择多了 3 个赋值语句,冒泡要交换数据,而插入排序只有一行的数据后移。

long time = 0;
for (int j = 0; j < 20; j++) {
    int[] arr = new int[10000];
    for (int i = 0; i < 10000; i++) {
        arr[i] = (int) (Math.random() * 10000);
    }
    long begin = System.currentTimeMillis();
    bubbleSort(arr, arr.length);
    time += System.currentTimeMillis() - begin;
}
System.out.println(time);

插入排序的链表实现

public static Node insertSort(Node head) {
    if (head == null || head.next == null) return head;

    Node pOrder = head; //有序链表中的游动指针
    Node pWait = head.next; //无序链表中的第一个待排序节点
    Node insertNode;  //要插入的节点
    Node ppOrder;//指向pOrder的前一个节点
    //将有序和无序部分断开
    pOrder.next = null;

    while (pWait != null) {
        ppOrder = pOrder = head;
        insertNode = pWait;
        pWait = pWait.next;
        insertNode.next = null;
        //插入过程
        while (pOrder != null) {
            if (insertNode.data < pOrder.data) {
                if (pOrder == head) {  //插在首位
                    insertNode.next = head;
                    head = insertNode;
                    break;
                } else {  //在中间
                    insertNode.next = pOrder;
                    ppOrder.next = insertNode;
                    break;
                }
            }

            //向后寻找比insert大的节点
            ppOrder = pOrder;
            pOrder = pOrder.next;
        }
		//插入结尾
        if (pOrder == null) ppOrder.next = insertNode;
    }
    return head;
}

猜你喜欢

转载自blog.csdn.net/weixin_41889284/article/details/87927097