十大排序算法

参考博文十大算法实现 JAVA版本
今天学习了下排序算法,参照别人的思路,自己实现了一次。此文作为今天学习的总结,以便以后复习查看。这篇博客中所提到的所有排序算法均以从小到大排序为例,其他情况请自行类比。

一.基本概念

1.算法分类

十大排序算法_第1张图片

2.算法复杂度比较

十大排序算法_第2张图片

二.各种算法实现及思路

1.冒泡排序

1.1算法描述

1)比较相邻的元素。如果前一个比后一个大,就交换它们两个;
2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
3)针对所有的元素重复以上的步骤,除了最后一个;
4)重复步骤1~3,直到排序完成。为了优化算法,可以设立一个布尔标识,每趟排序开始前设为false,如果该趟排序发生了交换就置为true,如果一趟排序结束标识仍为false表示该趟排序没有发生交换,即数组已经有序,可以提前结束排序。

1.2算法实现

//冒泡排序
    public static void bubbleSort(int[]array){
        int length=array.length;
        boolean flag;//标志位
        for(int i=0;iarray[j+1]){
                    swap(array,j,j+1);
                    flag=false;
                }
            }
            if(flag==true)
                break;
        }
    }
    private static void swap(int[]array,int i,int j){
        int temp=array[i];
        array[i]=array[j];
        array[j]=temp;
    }

1.3鸡尾酒算法

鸡尾酒算法是对冒泡算法的改进,将大的数往后冒泡,小的数往前冒泡

//鸡尾酒排序
    //冒泡的改进,最大的往后面冒泡的同时最小的往前面冒泡
    public static void cocktailSort(int[] array) {
        int left=0;
        int right=array.length-1;
        while(leftarray[i+1]){
                    swap(array,i,i+1);
                }
            }
            right--;
            //最小的往前面冒泡
            for(int i=right;i>left;i--){
                if(array[i]

2.快速选择排序

2.1算法描述

1)遍历一次数组,找到最小值与数组首元素交换,这时候数组首元素为排序区,后面为非排序区
2)找到非排序区的最小值,放在排序区后
3)重复2)步骤,直到非排序区为空

2.2算法实现

//简单选择排序
    //每次遍历把最小的插入到前面
    public static void selectionSort(int[] array) {
        int length=array.length;
        for(int i=0;i

3.直接插入排序

3.1算法描述

直接插入排序算法有点像摸扑克牌,手牌是已经排好序的,这时候从牌组里摸一张牌,比较摸牌和手牌的大小,然后插入牌。
1)从第一个元素开始,该元素可以认为已经被排序;
2)取出下一个元素,在已经排序的元素序列中从后向前扫描;
3)如果该元素(已排序)大于新元素,将该元素移到下一位置;
4)重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5)将新元素插入到该位置后;
6)重复步骤2~5

3.2算法实现

//直接插入排序
    //是对排序好的数组进行排序,即把数字插入排序好的数组
    public static void insertionSort(int[] array) {
        int length=array.length;
        for(int i=1;i=0&¤t

4.希尔排序

4.1算法描述

希尔排序是直接插入排序的改进,也可以说直接插入排序是希尔排序的特例,将gap设为1就是上面的实现直接排序。先将整个待排元素序列分割成 gap 个增量为 gap 的子序列(每个子序列由位置相差为 gap 的元素组成,整个序列正好分割成 gap 个子序列,每个序列中有 n / gap 个元素)分别进行直接插入排序,然后缩减增量为之前的一半再进行排序,待 gap == 1时,希尔排序就变成了直接插入排序。因为此时序列已经基本有序,直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的。gap初始值一般取 len / 2。

4.2算法实现

//希尔排序
    //直接插入排序的改进版
    public static void ShellSort(int[] array) {
        int length=array.length;
        int gap=length/2;

        while(gap>0){
            for(int i=gap;i=0&¤t

5.归并排序

5.1算法描述

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
分治的基本思想如下:
分治法在每一层递归上都有三个步骤:
  step1 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
  step2 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
  step3 合并:将各个子问题的解合并为原问题的解。
  它的一般的算法设计模式如下:
  Divide-and-Conquer(P)
  1. if |P|≤n0
  2. then return(ADHOC(P))
  3. 将P分解为较小的子问题 P1 ,P2 ,…,Pk
  4. for i←1 to k
  5. do yi ← Divide-and-Conquer(Pi) △ 递归解决Pi
  6. T ← MERGE(y1,y2,…,yk) △ 合并子问题
  7. return(T)
  其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时直接用算法ADHOC(P)求解。算法MERGE(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,…,Pk的相应的解y1,y2,…,yk合并为P的解。
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;

5.2算法实现

  //归并排序
    public static void mergeSort(int[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    public static void sort(int[] arr, int L, int R) {
        if(L == R) {
            return;
        }
        int mid = L + ((R - L) >> 1);
        sort(arr, L, mid);
        sort(arr, mid + 1, R);
        merge(arr, L, mid, R);
    }

    public static void merge(int[] arr, int L, int mid, int R) {
        int[] temp = new int[R - L + 1];
        int i = 0;
        int p1 = L;
        int p2 = mid + 1;
        // 比较左右两部分的元素,哪个小,把那个元素填入temp中
        while(p1 <= mid && p2 <= R) {
            temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        // 上面的循环退出后,把剩余的元素依次填入到temp中
        // 以下两个while只有一个会执行
        while(p1 <= mid) {
            temp[i++] = arr[p1++];
        }
        while(p2 <= R) {
            temp[i++] = arr[p2++];
        }
        // 把最终的排序的结果复制给原数组
        for(i = 0; i < temp.length; i++) {
            arr[L + i] = temp[i];
        }
    }

6.快速排序

6.1算法描述

1.在数组中选一个基准数(通常为数组第一个);

2.将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边;

3.对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。

6.2算法实现

快排也是采用了分治的思想。

public static int partition(int[] array,int left,int right) {
        int key=array[right];//初始坑
        while(left=key&&left

你可能感兴趣的:(十大排序算法)