JavaScript 排序算法

排序算法:

冒泡排序:频繁交换 ,找出其中最大的放到最后一个 一次找到第二大的放大倒数第二个...最后完成

function bubbleSort(arr) {
            for (let i = 0;i < arr.length - 1;i++) {
                for (let j = 0;j < arr.length - 1 - i;j++) {
                    if (arr[j] > arr[j + 1]) {
                        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
                    }

                }
            }
    return arr;
}

选择排序:
从开头选择一个基准值 遍历一趟选出比这个更小的值最后当前位置与找出来的最终值交换。排列顺序是从前到后

function xuanzeSort(arr) {
            for (let i = 0, min, index;i < arr.length;i++) {
                min = arr[i];
                index = i;
                for (let j = i + 1;j < arr.length;j++) {
                    if (min > arr[j]) {
                        min = arr[j];
                        index = j;
                    }
                }
                arr[index] = arr[i]
                arr[i] = min;
            }
            return arr;
        }

插入排序:
跟我们的打牌一样: 从第一个开始 拿到这个值往前比较 找到比它小的值的时候停下来放在这里,简单就是 找到合适的位置然后插入进去

function charuSort(arr) {
            let index, current;
            for (let i = 1;i < arr.length;i++) {
                index = i - 1;
                current = arr[i]
                while (current < arr[index] && index >= 0) {
                    arr[index + 1] = arr[index];
                    index--;
                }
                arr[index + 1] = current;
            }
            return arr;
        }

快速排序
把数据分成两组,选择最中间的一个值 前后分成两个,比中间这个值大的放后面 比这个值小的放在前面。然后递归排列前后数组即可

var quickSort = function (arr) {
            if (arr.length <= 1) { return arr; }
            var pivotIndex = Math.floor(arr.length / 2);
            var pivot = arr.splice(pivotIndex, 1)[0];
            var left = [];
            var right = [];
            for (var i = 0;i < arr.length;i++) {
                if (arr[i] < pivot) {
                    left.push(arr[i]);
                } else {
                    right.push(arr[i]);
                }
            }
            return quickSort(left).concat([pivot], quickSort(right));
        };

希尔排序:是对插入排序的优化。插入排序一次移动一位,而希尔排序是一次移动gap位。
 希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
为更加清晰地说明该排序,贴一张其它地方转载而来的图片

图片

这个代码我看了好一段时间,都有点懵 难理解,最后弄个例子程序一步一步走才看懂了。哎 我真笨
其实这个图对我来说有点误导性。
图上看起来是一组一组的排好序的,但是并不是。 而是设置一个值j = gap的时候,就依次排,排到最后一个 ,只是移动的间隔为gap。上图上的分组是同时在进行排序。这样排到后面的时候前面相应间隔的数是已经排好序了的。

//希尔排序
        function shellSort(arr) {
            let len = arr.length;
            // gap 即为增量
            for (let gap = Math.floor(len / 2);gap > 0;gap = Math.floor(gap / 2)) {
                debugger
                for (let i = gap;i < len;i++) {
                    let j = i;
                    let current = arr[i];
                    while (j - gap >= 0 && current < arr[j - gap]) {
                        arr[j] = arr[j - gap];
                        j = j - gap;
                    }
                    arr[j] = current;
                }
            }
            return arr;
        }

        let arr = [8, 5, 6, 1, 7, 3, 2, 4];
        console.log(shellSort(arr));

希尔排序比直接插入排序优点:
直接插入排序的问题:如果在后面来了一个特别小的元素,需要全部移动,那么排序的效率特别低。
希尔排序优点:如果在数组最后加入一个小元素,他会被很快移到最前面。
归并排序
基本思想:先递归的分解数列,再合并数列
(1)将一个数组拆成A、B两个小组,两个小组继续拆,直到每个小组只有一个元素为止。
(2)按照拆分过程逐步合并小组,由于各小组初始只有一个元素,可以看做小组内部是有序的,合并小组可以被看做是合并两个有序数组的过程。
(3)对左右两个小数列重复第二步,直至各区间只有1个数。
代码实现:

        //辅助函数,传入两个数组,按大小顺序插入新数组然后返回。
        function Merger(a, b) {
            var n = a && a.length;
            var m = b && b.length;
            var c = [];
            var i = 0, j = 0;

            while (i < n && j < m) {
                if (a[i] < b[j])
                    c.push(a[i++]);
                else
                    c.push(b[j++]);
            }

            while (i < n)
                c.push(a[i++]);

            while (j < m)
                c.push(b[j++]);

            console.log("将数组", a, '和', b, '合并为', c)
            return c;
        }
      
//划分数组
        function merge_sort(arr) {
            console.log(arr)
            if (arr.length == 1)
                return arr

            var mid = Math.floor(arr.length / 2)
            var left = arr.slice(0, mid)
            var right = arr.slice(mid)

            return Merger(merge_sort(left), merge_sort(right)); //合并左右部分
        }
        let arr = [8, 5, 6, 1, 7, 3, 2, 4];
        console.log(merge_sort(arr));

原文:归并排序

堆排序
大佬链接:堆排序
前面步骤看懂了,后面看代码有点绕

//堆排序
        // 交换两个节点
        function swap(A, i, j) {
            let temp = A[i];
            A[i] = A[j];
            A[j] = temp;
        }

        // 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
        // 假设 结点 i 以下的子堆已经是一个大顶堆,shiftDown函数实现的
        // 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。后面
        // 将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
        // 都执行 shiftDown操作,所以就满足了结点 i 以下的子堆已经是一大
        //顶堆
        function shiftDown(A, i, length) {
            let temp = A[i]; // 当前父节点
            // j<length 的目的是对结点 i 以下的结点全部做顺序调整
            for (let j = 2 * i + 1;j < length;j = 2 * j + 1) {
                temp = A[i];  // 将 A[i] 取出,整个过程相当于找到 A[i] 应处于的位置
                if (j + 1 < length && A[j] < A[j + 1]) {
                    j++;   // 找到两个孩子中较大的一个,再与父节点比较
                }
                if (temp < A[j]) {
                    swap(A, i, j) // 如果父节点小于子节点:交换;否则跳出
                    i = j;  // 交换后,temp 的下标变为 j
                } else {
                    break;
                }
            }
        }

        // 堆排序
        function heapSort(A) {
            // 初始化大顶堆,从第一个非叶子结点开始
            debugger
            for (let i = Math.floor(A.length / 2 - 1);i >= 0;i--) {
                shiftDown(A, i, A.length);
            }
            
            // 排序,每一次for循环找出一个当前最大值,数组长度减一
            for (let i = Math.floor(A.length - 1);i > 0;i--) {
                swap(A, 0, i); // 根节点与最后一个节点交换
                shiftDown(A, 0, i); // 从根节点开始调整,并且最后一个结点已经为当
                // 前最大值,不需要再参与比较,所以第三个参数
                // 为 i,即比较到最后一个结点前一个即可
            }
            return A;
        }

        let arr = [8, 5, 6, 1, 7, 3, 2, 4];
        console.log(heapSort(arr));

下面循环调用的shiftDown的时候 是从上到下,并把下面的非叶子节点的大小顺序移动(??)
暂时不懂 有空再弄
堆排序是不同的选择排序。

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