图解排序算法(一)之3种简单排序(选择,冒泡,直接插入)

  排序是数据处理中十分常见且核心的操做,虽然说实际项目开发中很小概率会须要咱们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现。可是了解这些精妙的思想对咱们仍是大有裨益的。本文简单温习下最基础的三类算法:选择,冒泡,插入。算法

  先定义个交换数组元素的函数,供排序时调用数组

   /**
     * 交换数组元素
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int []arr,int a,int b){
        arr[a] = arr[a]+arr[b];
        arr[b] = arr[a]-arr[b];
        arr[a] = arr[a]-arr[b];
    }

简单选择排序

  简单选择排序是最简单直观的一种算法,基本思想为每一趟从待排序的数据元素中选择最小(或最大)的一个元素做为首元素,直到全部元素排完为止,简单选择排序是不稳定排序函数

  在算法实现时,每一趟肯定最小元素的时候会经过不断地比较交换来使得首位置为当前最小,交换是个比较耗时的操做。其实咱们很容易发现,在还未彻底肯定当前最小元素以前,这些交换都是无心义的。咱们能够经过设置一个变量min,每一次比较仅存储较小元素的数组下标,当轮循环结束以后,那这个变量存储的就是当前最小元素的下标,此时再执行交换操做便可。代码实现很简单,一块儿来看下。性能

  代码实现优化

    /**
     * 简单选择排序
     *
     * @param arr
     */
    public static void selectSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;//每一趟循环比较时,min用于存放较小元素的数组下标,这样当前批次比较完毕最终存放的就是此趟内最小的元素的下标,避免每次遇到较小元素都要进行交换。
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[min]) {
                    min = j;
                }
            }
            //进行交换,若是min发生变化,则进行交换
            if (min != i) {
                swap(arr,min,i);
            }
        }
    } 

  简单选择排序经过上面优化以后,不管数组原始排列如何,比较次数是不变的;对于交换操做,在最好状况下也就是数组彻底有序的时候,无需任何交换移动,在最差状况下,也就是数组倒序的时候,交换次数为n-1次。综合下来,时间复杂度为O(n2)spa

冒泡排序 

  冒泡排序的基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到彻底有序code

  

  代码实现blog

    在冒泡排序的过程当中,若是某一趟执行完毕,没有作任何一次交换操做,好比数组[5,4,1,2,3],执行了两次冒泡,也就是两次外循环以后,分别将5和4调整到最终位置[1,2,3,4,5]。此时,再执行第三次循环后,一次交换都没有作,这就说明剩下的序列已是有序的,排序操做也就能够完成了,来看下代码 排序

 /**
     * 冒泡排序
     *
     * @param arr
     */
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            boolean flag = true;//设定一个标记,若为true,则表示这次循环没有进行交换,也就是待排序列已经有序,排序已然完成。
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr,j,j+1);
                    flag = false;
                }
            }
            if (flag) {
                break;
            }
        }
    }

  根据上面这种冒泡实现,若原数组自己就是有序的(这是最好状况),仅需n-1次比较就可完成;如果倒序,比较次数为 n-1+n-2+...+1=n(n-1)/2,交换次数和比较次数等值。因此,其时间复杂度依然为O(n2。综合来看,冒泡排序性能还仍是稍差于上面那种选择排序的。开发

直接插入排序

  直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完全部元素为止。

   

代码实现 

    /**
     * 插入排序
     *
     * @param arr
     */
    public static void insertionSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int j = i;
            while (j > 0 && arr[j] < arr[j - 1]) {
                swap(arr,j,j-1);
                j--;
            }
        }
    }

  简单插入排序在最好状况下,须要比较n-1次,无需交换元素,时间复杂度为O(n);在最坏状况下,时间复杂度依然为O(n2)。可是在数组元素随机排列的状况下,插入排序仍是要优于上面两种排序的。

总结

  本文列举了排序算法中最基本的三种算法(简单选择,冒泡,插入),这三种排序算法的时间复杂度均为O(n2),后续会陆续更新其余更高阶一些的排序算法,时间复杂度也会逐步突破O(n2),谢谢支持。

相关文章
相关标签/搜索