排序算法十大(后续再把未完成的进行一个更新)

排序算法

排序的定义

所谓排序,就是使一串记录,按照其中的某个或某个关键字的大小,递增递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。

排序算法的评价标准:

1、时间复杂度

2、空间复杂度

3、使用场景

4、稳定性

算法的分类

排序算法大致可以分为内部算法和外部算法。如果整个排序过程不需要借助于外部储存器(磁盘),所有的操作都在内存中完成,则称之为内部算法。如果参与排序树数据元素非常多,数据量非常大,则计算机必须借助外部储存器(如磁盘),这种排序称为外部排序。

image-20201125141521922

1、冒泡排序(Buddle Sort)

定义

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

img

算法描述:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

Java实现

public static int[] Buddle_sort(int[] array){
    if (array.length==0){
        return array;
    }
    for (int i = 0; i < array.length-1; i++) {
        for (int j = 0; j < array.length-1-i; j++) {
            if (array[j]>array[j+1]){
                int temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    return array;
}
public static void main(String[] args) {
    int[] a = {2,44,38,5,47,36,26,27,4,19,50,48,5,3};
    System.out.println(Arrays.toString(Buddle_sort(a)));
}

算法分析

最佳情况:T(n) = O(n) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)

2、选择排序(Selection Sort)

定义

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

算法描述:

  • 初始状态:无序区为R[1…n],有序区为空;
  • 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • n-1趟结束,数组有序化了。

img

java实现

//选择排序
public static int[] Selection_sort(int[] array){
    int tag = 0;//记录下标
    int temp =0;//交换中介
    if (array.length==0){
        return array;
    }
    for (int i = 0; i < array.length-1; i++) {
        tag = i;
        for (int j = i+1; j < array.length; j++) {
            if (array[tag]>array[j]){
                tag=j;//记录最小数的下标索引
            }
        }
        //比较完成,进行交换
        temp = array[tag];
        array[tag] = array[i];
        array[i] = temp;
    }
    return array;
}

算法分析

表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度!

最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)

3、插入排序(Insertion Sort)

定义

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

算法描述:

  • 从第一个元素开始,该元素可以认为已经被排序;
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  • 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  • 将新元素插入到该位置后;
  • 重复步骤2~5。

img

java代码实现

//插入排序
public static int[] Insert_sort(int[] array){
    if (array.length==0){
        return array;
    }
    int preIndex =0;//前一个下标索引
    int current=0;//要插入的数据
    for (int i = 1; i < array.length; i++) {
        current = array[i];
        preIndex = i-1;
        //查找数据的位置进行插入,对有序数组的数据进行逐个比较,找到位置之后结束循环
        while (preIndex>=0 && array[preIndex]>current){
            array[preIndex+1] = array[preIndex];
            preIndex--;
        }
        //找到数据的插入位置preIndex+1
        array[preIndex+1] = current;
    }
    return array;
}

算法的分析

插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

最佳情况:T(n) = O(n) 最坏情况:T(n) = O(n2) 平均情况:T(n) = O(n2)

4、归并排序(Merge Sort)

定义

归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

算法描述:

  • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  • 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  • 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  • 重复步骤3直到某一指针超出序列尾
  • 将另一序列剩下的所有元素直接复制到合并序列尾

简单描述

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列

img

java代码实现

/*
* @paragm array[]
* @return 
* */
//对当前的数组进行折半然后归并排序,使用的递归自下而上
public static int[] Merge_sort(int[] array){
    if (array.length<2){return array;}
    int middle = array.length/2;

    int[] left = Arrays.copyOfRange(array, 0, middle);
    int[] right = Arrays.copyOfRange(array, middle, array.length);

    return merge(Merge_sort(left),Merge_sort(right));
}

//归并排序:将俩个排序好的数据合成一个排序数组
/*
* @param left
* @param right
* */
public static int[] merge(int[] left,int[] right){
    //创建一个数据result用来存放合成的数组
    int[] result = new int[left.length+ right.length];

    int i =0;//result数组的下标

    while (left.length>0 && right.length >0){
        if (left[0] >= right[0]){
            result[i++] = right[0];
            right = Arrays.copyOfRange(right,1,right.length);
        }
        else {
            result[i++] = left[0];
            left = Arrays.copyOfRange(left,1,left.length);
        }
    }
    //因为可能出现left或者right中的一方先完成数据的插入,所以我们要对剩下的另一方完成剩下的数据的插入

    while (left.length>0){
        result[i++] = left[0];
        left = Arrays.copyOfRange(left,1,left.length);
    }

    while (right.length>0){
        result[i++] = right[0];
        right = Arrays.copyOfRange(right,1,right.length);
    }
    return result;
}
public static void main(String[] args) {
    int[] a = {2,44,38,5,47,36,26,27,4,19,50,48,5,3};
    System.out.println(Arrays.toString(Merge_sort(a)));

}

算法分析:

归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。

最佳情况:T(n) = O(n) 最差情况:T(n) = O(nlogn) 平均情况:T(n) = O(nlogn)

5、希尔排序(Shell Sort)

定义

希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。

算法描述:

  • 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  • 按增量序列个数k,对序列进行k 趟排序;
  • 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

原始数组:颜色相同的为一组

image-20201126194841907

初始增量为gap=length/2=5,整个数组被分为俩组,[7,6],[4,2].[9,8],[1,3],[5,10]

对5组分别进行直接插入排序,结果如下:

woisxkfzq

缩小增量gap=5/2=2,数组别分为俩组

image-20201126195605907

woisxkfzq2

image-20201126201300740

再缩小增量gap=2/2=1,数组变为一组

image-20201126201406775

最后再进行插入排序

image-20201126201502448

java代码实现

public static int[] Shell_sort(int[] array){
    int gap= array.length/2;//定义增量gap,这里我们以gap/2来缩小增量
    int temp;//交换中介
    while (gap>0) {
        for (int i = gap; i < array.length; i++) {
            temp = array[i];
            int preIndex = i - gap;
            while (preIndex >= 0 && array[preIndex] > array[i]) {
                array[preIndex + gap] = array[preIndex];
                preIndex -= gap;
            }
            array[preIndex + gap] = temp;
        }
        //进行完增量gap分组的排序后。对增量进行缩减
        gap /= 2;
    }
    return array;
}

算法分析

希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。

最佳情况:T(n) = O(nlog2 n) 最坏情况:T(n) = O(nlog2 n) 平均情况:T(n) =O(nlog2n)

6、快速排序(Quick Sort)

定义

快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

算法描述:

  • 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)
  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

java代码实现

/*
* @param   int[] array 要进行快速排序的数组
* @return
* */
public static void quick_sort(int[] array,int left,int right){
  if (left<right){
      int mid = get_mid(array,left,right);//中枢
      quick_sort(array,left,mid-1);
      quick_sort(array,mid+1, right);
  }

}

private static int get_mid(int[] array, int left, int right) {
    int pivot = array[left];//基准pivot
    while (left<right){
        while (array[right]>=pivot &&left<right) right--;
        if (array[right]<pivot){ array[left] = array[right];}
        while (array[left]<pivot && left<right) left++;
        if (array[left]>pivot){ array[right] = array[left];}
    }
    array[left] = pivot;
    return left;

}

算法分析:

最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(nlogn)

7、堆排序(Heap Sort)

定义

Heapsort)是指利用这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

算法描述:

  • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

8基数排序

9桶排序

10计数排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMyTIKDe-1616729711995)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224141901495.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fwMoU7N8-1616729711996)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144722675.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFhRoPci-1616729711997)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144733301.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDQlUsD1-1616729711998)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144750039.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wpHZ1FZ-1616729711999)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144757208.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHWChIx8-1616729712000)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144812328.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dpCtGDes-1616729712001)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144833397.png)]

  • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

8基数排序

9桶排序

10计数排序

[外链图片转存中…(img-EMyTIKDe-1616729711995)]

[外链图片转存中…(img-fwMoU7N8-1616729711996)]

[外链图片转存中…(img-WFhRoPci-1616729711997)]

[外链图片转存中…(img-kDQlUsD1-1616729711998)]

[外链图片转存中…(img-2wpHZ1FZ-1616729711999)]

[外链图片转存中…(img-lHWChIx8-1616729712000)]

[外链图片转存中…(img-dpCtGDes-1616729712001)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hwm1Pb5Q-1616729712003)(%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95.assets/image-20201224144841814.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值