排序

常见的八种排序算法


排序算法结构图

各种排序算法的比较

不稳定:快选堆希
稳 定:插冒归基


直接插入排序:

算法思想:
将数组中所有的元素与前面已经排好序的元素进行比较,如果选择的元素比已排序的元素小,则交换
使用两个循环完成
第一层循环:遍历待比较的所有元素
第二层循环:将本轮选择的元素与已经排好序的元素相比较,如果选择的元素比已排序的元素小,则交换

  • 时间复杂度:
    平均情况:O(n2)
    最好情况:O(n) 已排好序的数列
    最坏情况:O(n2) 逆序的数列
  • 空间复杂度:O(1)
  • 稳定性:稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j > -1; j-- ) {
        if (arr[j] < arr[j - 1]) {
            var t = arr[j];
            arr[j] = arr[j - 1];
            arr[j - 1] = t;
        }
    }
}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


希尔排序

算法思想:
将数组按下标进行一定增量的分组,对每组使用插入算法排序,随着增量的减少,每组包含的数据会越来越多,当增量为1时,整个数组都被分到一组,算法即终止。

  • gap(增量):length / 2 ,而后依次以gap = gap / 2,所以增量序列为{length / 2, (length / 2) / 2, ..., 1}
    注意: 希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。
  • 时间复杂度:
    平均情况:O(n2)
    最好情况:O(n)
    最坏情况:O(n2)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var gap = Math.floor(arr.length / 2); gap >= 1; gap = Math.floor(gap / 2)) {
    console.log('gap = ', gap);    //gap =  4, gap = 2, gap = 1
    for (var i = gap; i < arr.length; i++) {
        for (var j = i; j >= 0; j -= gap) {
            if (arr[j] < arr[j - gap]) {
                var t = arr[j];
                arr[j] = arr[j - gap];
                arr[j - gap] = t;
            }
        }
    }

}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


简单排序

算法思想:

  1. 从待排序的序列中,找到最小的元素;
  2. 如果最小元素不是第一个,将把最小元素与第一个交换,将余下的元素置为待排序元素,重复1,2步骤,直到待排序元素为1。
  • 时间复杂度:
    平均情况:O(n2)
    最好情况:O(n2)
    最坏情况:O(n2)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j < arr.length; j++) {
        if (arr[j] < arr[i]) {
            var t = arr[j];
            arr[j] = arr[i];
            arr[i] = t;
        }
    }
}

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 8, 7, 9 ]


堆排序

算法思想:

  1. 将待排序序列构造成一个大顶堆(小顶堆),堆顶的根节点就是整个序列最大值(最小值);
  2. 然后将其与末尾元素进行交换,此时末尾元素就是最大值(最小值)了;
  3. 将剩余的元素构造成一个堆,重复1,2,3步骤,直到剩余的元素为1。

注:
堆:堆是满足大顶堆或小顶堆的完全二叉树
大顶堆:每个结点的值都大于或等于其左右孩子结点的值
小顶堆:每个结点的值都小于或等于其左右孩子结点的值

  • 时间复杂度:
    平均情况:O(nlog2n)
    最好情况:O(nlog2n)
    最坏情况:O(nlog2n)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function ajustArr(arr, i, length) {
    for (var j = i * 2 + 1; j < length; j = j * 2 + 1) {
        if ((j + 1 < length) && (arr[j] < arr[j + 1])) {
            j++;
        }

        if (arr[j] > arr[i]) {
            var t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
            i = j;
        }

    }
}

function makeHeap(arr, n) {
    for (var i = Math.floor(n / 2 - 1); i >= 0; i--) {
        ajustArr(arr, i, n);
    }
}

function heapSort(arr) {
    makeHeap(arr, arr.length);
    for (var i = arr.length - 1; i >= 0; i--) {
        
        console.log(arr);   
        // [ 9, 8, 6, 7, 5, 1, 4, 2, 3 ]
        // [ 8, 7, 6, 3, 5, 1, 4, 2, 9 ]
        // [ 7, 5, 6, 3, 2, 1, 4, 8, 9 ]
        // [ 6, 5, 4, 3, 2, 1, 7, 8, 9 ]
        // [ 5, 3, 4, 1, 2, 6, 7, 8, 9 ]
        // [ 4, 3, 2, 1, 5, 6, 7, 8, 9 ]
        // [ 3, 1, 2, 4, 5, 6, 7, 8, 9 ]
        // [ 2, 1, 3, 4, 5, 6, 7, 8, 9 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

        var t = arr[i];
        arr[i] = arr[0];
        arr[0] = t;
        ajustArr(arr, 0, i);
    }
}

heapSort(arr);

console.log(arr);   // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


冒泡排序

算法思想:

  1. 将序列中的左右元素进行比较,保证右边的元素始终大于(小于)左边的元素;
  2. 循环执行步骤1,执行完成后,序列的最后一个元素即为当前序列的最大值(最小值);
  3. 对剩余的元素循环执行步骤1,2,直到剩余的元素为1。
  • 时间复杂度:
    平均情况:O(n2)
    最好情况:O(n)
    最坏情况:O(n2)
  • 空间复杂度:O(1)
  • 稳定性:稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

for (var i = 0; i < arr.length; i++) {
    for (var j = i; j < arr.length; j++) {
        if (arr[j] > arr[j + 1]) {
            var t = arr[j + 1];
            arr[j + 1] = arr[j];
            arr[j] = t;
        }
    }
}
console.log(arr);   //[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


快速排序 (分治)

算法思想:

  1. 在列表中选择一个基准数(pivot)
  2. 将序列当中的所有数依次遍历,比基准数大的位于其右侧,比基准数小的位于其左侧
  3. 重复步骤1,2,直到所有子集当中只有一个元素为止。
  • 时间复杂度:
    平均情况:O(nlog2n)
    最好情况:O(nlog2n)
    最坏情况:O(n2)
  • 空间复杂度:O(nlog2n)
  • 稳定性:不稳定
var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function quickSort(arr, start, end) {
    if (start < end) {
        var pivot = arr[start];
        var left = start;
        var right = end;

        while(left < right) {
            while((left < right) && (pivot <= arr[right]))  right--;
            if (left < right) {
                arr[left] = arr[right];
                left++;
            }
            while((left < right) && (pivot >= arr[left]))  left++;
            if (left < right) {
                arr[right] = arr[left];
                right--;
            }
        }

        arr[left] = pivot;
        console.log(arr);   
        // [ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 9, 8, 7 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

        quickSort(arr, left + 1, end);
        quickSort(arr, start, left - 1);
    }
}
quickSort(arr, 0, arr.length - 1);

console.log(arr);   //[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]


归并排序(分治)

建立在归并操作上的排序算法,是分治法的典型应用。

算法思想:
将数据分为两组,如果组内数据只有一个时,认为组内数据有序,然后进行合并相邻的两组数据即可

  • 如何将两个有序数列合并?
    比较两个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数,然后再进行比较,如果数列为空,那就直接将另一个数列的数据依次取出。

  • 时间复杂度:
    平均情况:O(nlog2n)
    最好情况:O(nlog2n)
    最坏情况:O(nlog2n)

  • 空间复杂度:O(1)

  • 稳定性:稳定

var arr = [1, 3, 4, 2, 5, 6, 9, 8, 7];

console.log(arr);   //[ 1, 3, 4, 2, 5, 6, 9, 8, 7 ]

function mergeArr(arr, start, mid, end) {
    var tem = [], k = 0, i = start, j = mid + 1;
    while((i <= mid) && (j <= end)) {
        if (arr[i] <= arr[j]) {
            tem[k++] = arr[i++];
        } else {
            tem[k++] = arr[j++];
        }
    }

    while(i <= mid) {
        tem[k++] = arr[i++];
    }

    while(j <= end) {
        tem[k++] = arr[j++];
    }

    console.log('tem:', tem);
    // tem: [ 1, 3 ]
    // tem: [ 1, 3, 4 ]
    // tem: [ 2, 5 ]
    // tem: [ 1, 2, 3, 4, 5 ]
    // tem: [ 6, 9 ]
    // tem: [ 7, 8 ]
    // tem: [ 6, 7, 8, 9 ]
    // tem: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

    for (var i = 0; i < k; i++) {
        arr[start + i] = tem[i];
    }
}

function mergeSort(arr, start, end) {
    if (start < end) {
        var mid = Math.floor((start + end) / 2);
        mergeSort(arr, start, mid);
        mergeSort(arr, mid + 1, end);
        mergeArr(arr, start, mid, end);
    }
}

mergeSort(arr, 0, arr.length - 1);

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

推荐阅读更多精彩内容

  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,258评论 0 2
  • 0、排序算法说明 0.1 排序的定义 对一序列对象根据某个关键字进行排序。 0.2 术语说明 稳定:如果a原本在b...
    SithCait阅读 2,074评论 0 37
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,186评论 0 52
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,732评论 0 15
  • 2017年3月,我参加《故事的力量》课程认证,上课不久,老师让每人讲述自己的故事,很多人很快地讲述了自己的经历。我...
    王德岩阅读 556评论 0 5