排序算法整理

前言

  排序一直是算法中的经典和入门,也是一个合格的程序员应该随手都能够回答的问题。但是现实是,不经常写,不经常用的话,要是一下子让写或者让讲,估计有一半的人会呛住。

  在前年求职之前,系统的复习过所有经典的排序算法,也可以做到随手写出来的地步,但是前几天接触,突然发现自己都忘的差不多了,可能随手可以写个,选择,冒泡,插入排序,但是堆排(只知道最大堆的特性,基本忘记),快排和归并(只知道思路),所以写这篇文章的目的就是再重新花几天时间系统的再整理一下,复习一下,也以便于后续的温习。

概况

  排序顾名思义就是将一堆杂乱无章的数字,按照一定的规则(最大或者最小)进行排列的过程。

排序的分类
  • 按照是否将所有的记录全部加载到内存中进行排序分为:内部排序和外部排序

    img

  • 按照排序是否稳定分为:稳定排序和不稳定排序

    何谓稳定性?

    假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

  • 按照原理可以分为:插入排序,选择排序,交换排序,归并排序和基数排序

排序的方式

  经典的排序算法大致有以下10种

排序方法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性复杂性
直接插入排序O(n2)O(n2)O(n)O(1)稳定简单
希尔排序O(nlog2n)O(n2)O(n)O(1)不稳定较复杂
直接选择排序O(n2)O(n2)O(n2)O(1)不稳定简单
堆排序O(nlog2n)O(nlog2n)O(nlog2n)O(1)不稳定较复杂
冒泡排序O(n2)O(n2)O(n)O(1)稳定简单
快速排序O(nlog2n)O(n2)O(nlog2n)O(nlog2n)不稳定较复杂
归并排序O(nlog2n)O(nlog2n)O(nlog2n)O(n)稳定较复杂
基数排序O(d(n+r))O(d(n+r)))O(d(n+r))O(n+r)稳定较复杂

详情

插入排序
概念和原理

插入排序简单的讲就是从一堆无序的数据集中取出一个数,加入到有序的数据集中,直到所有的无序数据集都取完,那么有序的数据集就是排序后的数。

1527263835518

如上图所示,形象的解释了插入排序的原理。开始时,我们的左手为空并且桌子上的牌面向下,然后我们每次从桌子上拿走一张牌并将他们插入到左手中正确的位置,插入排序的原理由此而得。

思想

输入: 数组 A[1….n]

步骤:

​ 使用j作为标志位,j的左边为有序的数字,后边为无序的数字,那么初始j=2,最后n结束;

​ key=A[j]作为待插入的值,假设待加入的值是有序数组中的最大值,那么他的位置应该不变,那么如果不是呢?那么应该从有序数组的最后一个数A[i=j-1](有序数组中的最大值)进行比较,如果小,那么把这个大的数插入到j处,依次直到i>0&key>A[i],继续下一轮。

一句话概括:插入排序就是增熵减熵的过程

伪码
INSERTION-SORT(A)
// INSERTION-SORT
 for j=2 to A.length
     key = A[j]
     //insert A[j] into the sorted sequence A[1...j-1]
     i = j-1;
     while i>0 and A[i]>A[j]
        A[i+1] = A[i]
        i = i-1
     A[i+1] = key
实现

JAVA

  public int[] insert_sort(int []arrs){
        for(int j=1;j<arrs.length;j++){
            int key = arrs[j];
            int i = j-1;
            while(i>=0&&arrs[i]>key){
                arrs[i+1] = arrs[i];
                i--;
            }
            arrs[i+1] = key;
        }
        return arrs;
    }

    public static void main(String[] args) {
        int res[] = new Sort().insert_sort(new int[]{199,1,2,8,3});
        for (int e : res) {
            System.out.println(e);
        }
    }

1527412551814

JAVASCRIPT

var insert_sort = function (arrs){
    for(var j=1;j<arrs.length;j++){
        var key = arrs[j];
        var i = j-1;
        while(i>=0&&arrs[i]>key){
            arrs[i+1] = arrs[i];
            i--;
        }
        arrs[i+1] = key;
    }
}
var a = [199,1,2,8,3];
insert_sort(a)
console.log(a)  //1,2,3,8,199

时间复杂度

//todo

空间复杂度

//todo

稳定性

//todo

希尔排序
选择排序
概念和原理

选择排序就是就是从一堆数字中取出一个最小的放在一边,然后再去取一个最小的数,跟刚刚取出来的数字放一起,这样直到这堆数字被取完位置。

形象一点比如皇帝翻牌:heart_eyes_cat:,皇帝一天公务繁忙,晚上到了,这个时候太监就会走过来拿着下面的牌子让他选,这个是否皇帝会看一下都有哪些牌子,然后选择他最喜欢的一个妃子;如果皇帝觉得今天一个不够,还需要一个那么皇帝会在剩下的当中选择在他心中地位其次的妃子。

这个时候老佛爷说,皇帝你再选一个,这个时候皇帝又会在剩下的当中选择一个最好的。

1527414146675

皇帝选秀就是一个典型的选择排序问题

  现实生活中选择排序的思想运用的很多:挑衣服,挑零食等等,感觉选择排序的思想有点像贪心算法。

思路

1527413889306

该图阐述了选择排序的思想,从数组中遍历求出最小值,然后与连续的数组开头的组相互调换,直到所有的数都有序,排序结束

伪码
SELECTION-SORT(A)                        
   for j = 1 to Length(A)                            
       i = j                                                         
       key = A(i)                                              
       for i to Lenth(A)                                   
          if key>A(i)                                         
                key = A(i)   //当前最小值                                
                k = i        // 当前最小值的坐标                                  
       A(k) = A(j)     //把游标位置的数放到最小值的位置中区                                        
       A(j)  = key     //把最小值放入指定的游标位置                                     
实现

JAVA

 public void select_sort(int[] a) {
        if (a == null || a.length <= 0) {
            return;
        }
        for (int i = 0; i < a.length; i++) {
            int temp = a[i];
            int flag = i; // 将当前下标定义为最小值下标
            for (int j = i + 1; j < a.length; j++) {
                if (a[j] < temp) {// a[j] < temp 从小到大排序;a[j] > temp 从大到小排序
                    temp = a[j];
                    flag = j; // 如果有小于当前最小值的关键字将此关键字的下标赋值给flag
                }
            }
            if (flag != i) {
                a[flag] = a[i];
                a[i] = temp;
            }
        }
    }

    public static void main(String[] args) {
        int res[] = new int[] { 199, 1, 2, 8, 3 }; // 1,2,3,8,199
        new Sort().select_sort(res);
        for (int e : res) {
            System.out.println(e);
        }
    }

JAVASCRIPT

var select_sort = function(arrs) {
        if (arrs == null || arrs.length <= 0) {
            return;
        }
        for (var i = 0; i < arrs.length; i++) {
            var temp = arrs[i];
            var flag = i; // 将当前下标定义为最小值下标
            for (var j = i + 1; j < arrs.length; j++) {
                if (a[j] < temp) {// a[j] < temp 从小到大排序;a[j] > temp 从大到小排序
                    temp = a[j];
                    flag = j; // 如果有小于当前最小值的关键字将此关键字的下标赋值给flag
                }
            }
            if (flag != i) {
                a[flag] = a[i];
                a[i] = temp;
            }
        }
    }
var a = [199,1,2,8,3]; // 1,2,3,8,199
select_sort(a)
console.log(a)
时间复杂度

选择排序交换此处是处于0-(n-1)次之间,需要比较n(n-1) / 2次,赋值操作次数在0-3(n-1)次之间,因此平均时间复杂度为O(n2)

空间复杂度

O(1)

稳定性

序列{5 8 5 2 9}, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法

注:一般认为选择排序是不稳定排序,但是如果开辟一个新数组的话可以保证稳定性

冒泡排序
概念与原理

​ 冒泡的核心是一次bubble的过程,如下图所示,数组A[1…n]进过n-1次bubble过程就可以完成排序。

1527419114353

图中描述的是一次气泡(bubble)过程,小气泡12与相邻的对比,如果自己小,那么向上冒泡,一次冒泡过程就可以把最小的数冒泡到最上层。其余的无序数组也是利用类似的思想进行排序

伪码
BUBBLESORT(A)  
    for i = 1 to A.length-1   //总共bubble n-1次
        for j = A.length downto i + 1  //bubble的范围
            if A[j] < A[j - 1]  
                exchange A[j] with A[j - 1]  //bubble的过程
实现

JAVA

 public void bubble_sort(int []a){
        for(int i=0;i<a.length-1;i++){
            for(int j=0;j<a.length-1-i;j++){
                if(a[j+1]<a[j]){
                    int temp = a[j+1];
                    a[j+1] = a[j];
                    a[j] = temp;
                }
            }
        }
    }

JAVASCRIPT

var bubble_sort = function(a){
        for(var i=0;i<a.length-1;i++){
            for(var j=0;j<a.length-1-i;j++){
                if(a[j+1]<a[j]){
                    var temp = a[j+1];
                    a[j+1] = a[j];
                    a[j] = temp;
                }
            }
        }
}
var arrs = [76,18,99,35,12];
bubble_sort(arrs);
console.log(arrs);//12,18,35,76,99
时间复杂度

1527425711208

摘自百度百科

空间复杂度

O(1)

稳定性

冒泡排序比较是相邻的两个元素,交换也发生在这两个元素中。如果两个元素相等,不交换;如果两个相等元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值