常见的几种排序算法总结

对于非科班生的我来说,算法似乎对我来说是个难点,查阅了一些资料,趁此来了解一下几种排序算法。
首先了解一下,什么是程序

一个程序主要包括以下两方面的信息:
1、对数据的描述,在程序中要指定用到哪些数据类型以及这些数据的类型和数据的组织形式,这就是数据结构
2、对操作的描述,即要求计算机进行操作的步骤,就是算法
对于一种程序设计人员来说,算法,数据结构,程序化设计方法和程序语言是其所应的知识,算法是灵魂,数据结构是加工对象,语言是工具。

几种常见排序

关于排序算法通常我们所说的往往指的是内部排序算法,即数据记录在内存中进行排序。
排序算法大体可分为两种:
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等

1. 冒泡排序

1.1 简介

冒泡排序它重复地走访过要排序的元素,一次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。

1.2 实现过程
1.3 代码实现
function swap(myArray, p1, p2){
  var temp = myArray[p1];
  myArray[p1] = myArray[p2];
  myArray[p2] = temp;
}
function bubbleSort(myArray){
  var len = myArray.length;
  
  for (var i = 0; i < len - 1; i++){
    for (var j = 0; j < len - 1 - i; j++){
      if (myArray[j] > myArray[j + 1]){
        swap(myArray, j, j + 1);
      }
    }
  }
  return myArray;
}
bubbleSort([1,2,4,5,3]) //[1,2,3,4,5]

2 选择排序

2.1 简介

选择排序类似于冒泡排序,只不过选择排序是首先在未排序的序列中找到最小值(最大值),放到序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾,以此类推,直到所有元素均排序完毕。

2.2 实现过程
2.3 代码实现
function swap(myArray, p1, p2){
    var temp = myArray[p1];
    myArray[p1] = myArray[p2];
    myArray[p2] = temp;
}
function selectionSort(myArray){
    var len = myArray.length;
    var min;
    for (var i = 0; i < len; i++){
        // 将当前位置设为最小值
        min = i;
        // 检查数组其余部分是否更小
        for (var j = i+1; j < len; j++){
            if (myArray[j] < myArray[min]){
                min = j;
            }
        }
        // 如果当前位置不是最小值,将其换为最小值
        if (i !== min){
            swap(myArray, i, min);
        }
    }
    return myArray;
}
selectionSort([1,2,4,5,3])  //[1,2,3,4,5]

3 插入排序

3.1 简介

插入排序比冒泡排序和选择排序更有效率,插入排序类似于生活中抓扑克牌来。
插入排序具体算法描述,以数组[3, 2, 4, 5, 1]为例。

  1. 将数组分成[3]和[2, 4, 5, 1]两部分,前者是已排序的,后者是未排序的。
  2. 取出未排序部分的第一个元素“2”,与已排序部分最后一个元素“3”比较,因为2小于3,所以2排在3前面,整个数组变成[2, 3]和[4, 5, 1]两部分。
    3.取出未排序部分的第一个元素“4”,与已排序部分最后一个元素“3”比较,因为4大于3,所以4排在3后面,整个数组变成[2, 3, 4]和[5, 1]两部分。
  3. 取出未排序部分的第一个元素“5”,与已排序部分最后一个元素“4”比较,因为5大于4,所以5排在4后面,整个数组变成[2, 3, 4, 5]和[1]两部分。
  4. 取出未排序部分的第一个元素“1”,与已排序部分最后一个元素“5”比较,因为1小于5,所以再与前一个元素“4”比较;因为1小于4,再与前一个元素“3”比较;因为1小于3,再与前一个元素“2”比较;因为小于1小于2,所以“1”排在2的前面,整个数组变成[1, 2, 3, 4, 5]。
3.2 实现过程
3.3 代码实现
function insertionSort(myArray) {
    var len = myArray.length,     // 数组的长度
        value,                      // 当前比较的值
        i,                          // 未排序部分的当前位置
        j;                          // 已排序部分的当前位置
    
    for (i=0; i < len; i++) {    
        // 储存当前位置的值
        value = myArray[i];        
        /*
         * 当已排序部分的当前元素大于value,
         * 就将当前元素向后移一位,再将前一位与value比较
         */
        for (j=i-1; j > -1 && myArray[j] > value; j--) {
            myArray[j+1] = myArray[j];
        }
        myArray[j+1] = value;
    }    
    return myArray;
}
 insertionSort([1,2,4,5,3]) // [1,2,3,4,5]

4 归并排序

4.1 简介

前面三种排序算法只有教学价值,因为效率低,很少实际使用。归并排序(Merge sort)则是一种被广泛使用的排序方法。
它的基本思想是,将两个已经排序的数组合并,要比从头开始排序所有元素来得快。因此,可以将数组拆开,分成n个只有一个元素的数组,然后不断地两两合并,直到全部排序完成。
以对数组[3, 2, 4, 5, 1] 进行从小到大排序为例,步骤如下:

  1. 将数组分成[3, 2, 4]和[5, 1]两部分。
  2. 将[3, 2, 4]分成[3, 2]和[4]两部分。
  3. 将[3, 2]分成[3]和[2]两部分,然后合并成[2, 3]。
  4. 将[2, 3]和[4]合并成[2, 3, 4]。
  5. 将[5, 1]分成[5]和[1]两部分,然后合并成[1, 5]。
  6. 将[2, 3, 4]和[1, 5]合并成[1, 2, 3, 4, 5]。
4.2 实现过程
4.3 代码实现
function merge(left, right){
    var result  = [],
        il = 0,
        ir = 0;
    while (il < left.length && ir < right.length){
        if (left[il] < right[ir]){
            result.push(left[il++]);
        } else {
            result.push(right[ir++]);
        }
    }
    return result.concat(left.slice(il)).concat(right.slice(ir));
}
//上面的merge函数,合并两个已经按升序排好序的数组

有了merge函数,就可以对任意数组排序了。基本方法是将数组不断地拆成两半,直到每一半只包含零个元素或一个元素为止,然后就用merge函数,将拆成两半的数组不断合并,直到合并成一整个排序完成的数组。

function mergeSort(myArray){

    if (myArray.length < 2) {
        return myArray;
    }

    var middle = Math.floor(myArray.length / 2),
        left    = myArray.slice(0, middle),
        right   = myArray.slice(middle),
        params = merge(mergeSort(left), mergeSort(right));
    
    // 在返回的数组头部,添加两个元素,第一个是0,第二个是返回的数组长度
    params.unshift(0, myArray.length);

    // splice用来替换数组元素,它接受多个参数,
    // 第一个是开始替换的位置,第二个是需要替换的个数,后面就是所有新加入的元素。
    // 因为splice不接受数组作为参数,所以采用apply的写法。
    // 这一句的意思就是原来的myArray数组替换成排序后的myArray
    myArray.splice.apply(myArray, params);

    // 返回排序后的数组
    return myArray;
}
mergeSort([1,2,4,5,3]) // [1,2,3,4,5]

5 快速排序

5.1 简介

快速排序(quick sort)是公认最快的排序算法之一,有着广泛的应用。
快速排序算法步骤

  1. 从序列中挑出一个元素,作为"基准"(pivot).
  2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基 准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
  3. 对每个分区递归地进行步骤1~3,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
5.2 实现过程
5.3 代码实现
// 部署一个swap函数,用于互换两个位置的值。
function swap(myArray, firstIndex, secondIndex){
   var temp = myArray[firstIndex];
   myArray[firstIndex] = myArray[secondIndex];
   myArray[secondIndex] = temp;
}
// 部署一个partition函数,用于完成一轮排序。
function partition(myArray, left, right) {
    var pivot = myArray[Math.floor((right + left) / 2)],
        i = left,
        j = right;
    while (i <= j) {
        while (myArray[i] < pivot) {
            i++;
        }
        while (myArray[j] > pivot) {
            j--;
        }
        if (i <= j) {
            swap(myArray, i, j);
            i++;
            j--;
        }
    }
    return i;
}
// 递归上面的过程,完成整个排序。
function quickSort(myArray, left, right) {
    if (myArray.length < 2) return myArray;

    left = (typeof left !== "number" ? 0 : left);
    right = (typeof right !== "number" ? myArray.length - 1 : right);
    var index  = partition(myArray, left, right);

     if (left < index - 1) {
            quickSort(myArray, left, index - 1);
     }
     if (index < right) {
            quickSort(myArray, index, right);
      }
     return myArray;
}
quickSort([1,2,4,5,3]) // [1,2,3,4,5]

参考:
常用排序算法总结(一)
阮一峰-算法总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容