美文网首页Android开发
五种排序算法的学习

五种排序算法的学习

作者: 飘荡在空中 | 来源:发表于2019-12-25 16:37 被阅读0次

    前言

    现在计算机行业越来火爆, 因此许多人也加入这滚滚洪流. 本人作为小菜鸡一枚, 略有感悟五种小算法.因此随笔进行记录, 还会配以代码进行理解.
    我觉得, talk is cheap, show me the code 才是硬道理.

    Bubble Sort (冒泡排序)

    Nothing is better than pseudocode.

    function bubbleSort(A:list of sortable things)
      let n = length of A
      repeat
        swapped = false
        for i = 1 to n - 1 (inclusive) do
            if A[i - 1] > A[i] then
              swap(A[i - 1] and A[i])
              swapped = true
            end if 
        end for
    until not swapped
    end of function
    

    伪代码就是如上所示. 那么写成实现代码就好简单了. C++代码如下所示:

    // 首先我们写一个bubble 的过程
    void bubble(int arr[], int n) {
        int i;
        int temp;
        for (i = 0; i < n ; i++) {
            if (arr[i] > arr[i + 1]) {
                temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
            }
        }
    }
    // 然后我们可以就来做bubbleSort
    void bubbleSort(int arr[], int n) {
        for (int i = n; i >= 1; i--) {
            bubble(arr, i);
        }
    }
    

    接下来我们上测试代码。(C++菜鸡, java也是类似, 复制过去跑把。。。。)

    int main() {
        int arr[] = {6, 2, 4, 1, 7, 3, 8, 9};
        bubbleSort(arr, 8);
        for (int i = 0; i < 8; i++) {
            cout << arr[i] << " ";
        }
        return 0;
    }
    

    运行结果如下:


    冒泡排序

    我们可以来具体分析一下这个算法, 作为最简单的排序算法, 这个算法时间复杂度是O(n^2). 这个算法可能是最好掌握的一个方法, 但是我们仔细想想, 这个方法其实速度对于大规模排序来说就很容易挂了. 因此并不是一个常用(好用)的方法.相较于别的O(n^2)的方法, 比如插入排序,冒泡的表现也是比较糟糕的...

    SelectionSort (选择排序)

    选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n^2) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

    1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
    2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
      重复第二步,直到所有元素均排序完毕。

    废话不多说, 我们来看代码怎么写。我们先考虑选择过程

    int findMaxPos(int arr[], int n) {
        // 找出数组中最大元素的位置
        int pos = 0; // 假设你是最大的
        int max = arr[0];
        for (int i = 0; i <= n; i++) {
            if (arr[i] >= max) {
                max = arr[i];
                pos = i;
            }
        }
        return pos;
    }
    

    找出元素最大的位置之后, 我们来做排序。

    void selectionSort(int arr[], int n) {
        while (n > 0) {
            int pos = findMaxPos(arr, n);
            int tmp = arr[n];
            arr[n] = arr[pos];
            arr[pos] = tmp;
            n--;
        }
    }
    

    测试代码就自行测试把。
    算法分析: 时间复杂度 O(n^2)
    空间复杂度 O(1)
    表现也比较糟糕。。。。

    MergeSort(合并排序)

    这个方法是1945年由冯诺依曼这个人实现过.这个方法也是典型的分治法(Divide and Conquer). 作为典型的分治法,我们来看一下这个东西咋弄.

    /*MergeSort part.*/
        public void merge(int[] arr, int l, int m, int r) {
            // divide to 2 parts.
            int n1 = m - l + 1;
            int n2 = r - m;
            // then we need to allocate data.
            int[] L = new int[n1];
            int[] R = new int[n2];
            // copy data.
            for (int i = 0; i < n1; i++) {
                L[i] = arr[l + i];
            }
            for (int j = 0; j < n2; j++) {
                R[j] = arr[m + j + 1];
            }
    
            // then we need to merge.
            int i = 0, j = 0;
            int k = l;
            while (i < n1 && j < n2) {
                if (L[i] <= R[j]) {
                    arr[k] = L[i];
                    i++;
                } else {
                    arr[k] = R[j];
                    j++;
                }
                k++;
            }
    
            while (i < n1) {
                arr[k] = L[i];
                i++;
                k++;
            }
            while (j < n2) {
                arr[k] = R[j];
                j++;
                k++;
            }
        }
    
        public void mergeSort(int[] arr, int l, int r) {
            if (l < r) {
                int m = (r + l) / 2;
                mergeSort(arr, l, m);
                mergeSort(arr, m + 1, r);
                merge(arr, l, m, r);
            }
    
        }
    

    这个思路用的是递归(Recursive). 有兴趣的朋友可以思考一下迭代的怎么写.

    QuickSort(快速排序)

    /*Quick Sort*/
        public int partition(int[] arr, int low, int high) {
            // step 1. find a pivot.
            // let's suppose the pivot is the last one.
            int pivot = arr[high];
            // i is the variable to count, which idx we need to swap later?
    
            int i = low - 1;
            for (int j = low; j < high; j++) {
                if (arr[j] <= pivot) {
                    i++;
                    swap(arr, i, j);
                }
            }
            // after this, we need to swap
            swap(arr, i + 1, high);
            return i + 1;
        }
    
        public void quickSort(int[] arr, int low, int high) {
            if (low < high) {
                int pivot = partition(arr, low, high);
                quickSort(arr, low, pivot - 1);
                quickSort(arr, pivot + 1, high);
            }
    
        }
    

    插入排序

    首先考虑一个场景: 排序一手扑克牌。开始我们左手为空,桌子的牌朝下。然后, 我们每次从桌子上拿走一张牌, 把他插入到左手中正确的位置。

    仔细分析如上场景:

    • 我们左手的牌是始终保持有序的
    • 我们需要逐次查看我们有序的牌, 然后和我们新拿的牌作比较,决定插入位置
      这也是为什么他的名字叫插入排序。
      代码如下:
    public void insertionSort(int[] arr) {
            for (int j = 1; j < arr.length; j++) {
                int key = arr[j];
                int i = j - 1; // arr[0] 到 arr[i] 这部分是有序的, 等价上述场景的我们左手的牌
    
                while (i >= 0 && arr[i] >= key) {
                    // 移动位置, 找到牌合适的位置, 插入。
                    arr[i + 1] = arr[i];
                    i = i - 1;
                }
                arr[i + 1] = key;
            }
        }
    

    测试效果:

    int[] arr = {5, 2, 4, 6, 1, 3, 7};
    

    排序之后:


    排序后

    算法分析

    时间复杂度: O(n^2)。(当数组已经反向排序, 需要正向排序的时候)
    空间复杂度: O(1)

    相关文章

      网友评论

        本文标题:五种排序算法的学习

        本文链接:https://www.haomeiwen.com/subject/eozgwctx.html