排序算法2

归并排序

1)整体就是一个简单递归,左边排好序、右边排好序、让其整体有序
2)让其整体有序的过程里用了排外序方法

mergeSortTree

算法解析:
将整体进行左右分组,在分组过程中,对中间下标的计算采用mid = L + ((R - L) >> 1),而不是直接采用mid=(R+L)/2,目的是防止溢出,当R和L都比较大时,两者的和会超出数组长度;然后同样的方法将分好的组再进行左右分组,依次类推,最后将数分为两个一组或者单个数一组的形式,然后将每组中的数进行排序,小值位于前面,之后就是合并,在合并时,将前后两组的数,按照从左到右的顺序进行一一对比,按照从小到大的顺序排列好,以此类推,最后就能得到一个递增的数组。

function mergeSort(array) {
    if (array == null || array.length < 2) {
        return;
    }
    process(array, 0, array.length - 1);
}
function process(array, L, R) {
    if (L == R) {
        return;
    }
    var mid = L + ((R - L) >> 1);
    process(array, L, mid);
    process(array, mid + 1, R);
    merge(array, L, mid, R);
}
function merge(array, L, mid, R) {
    var help = [];
    var p1 = L;
    var p2 = mid + 1;
    while (p1 <= mid && p2 <= R) {
        help[i++] = array[p1] <= array[p2] ? array[p1++] : array[p2++];
    }
    while (p1 <= mid) {
        help[i++] = array[p1++];
    }
    while (p2 <= R) {
        help[i++] = array[p2++];
    }
    for (var i = 0; i < help.length; i++) {
        array[L + i] = help[i];
    }
}

归并排序的扩展

小和问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子:[1,3,4,2,5] 1左边比1小的数,没有; 3左边比3小的数,1; 4左边比4小的数,1,3; 2左边比2小的数,1; 5左边比5小的数,1、3、4、2; 所以小和为1+1+3+1+1+3+4+2=16。

小和问题就是采用了归并排序的方法,其中关键的一句代码就是res += array[p1] < array[p2] ? (R - p2 + 1) * array[p1] : 0;在两个小组中的数进行比较时,位于左边的组中的数,在右边组中遇到一个大于它的数时,res(R - p2 + 1) * array[p1],因为小组中数据已经进行了从小到大的排序,所以在遇到一个比它大的数时,这个数后面的数也都大于前面这组的这个数,所以对于array[p1]来说,它在小和中出现的次数就是(R-p2+1),然后乘以array[p1],累加在res中,最后就能得到整个数组的小和。

function smallSort(array) {
    if (array == null || array.length < 2) {
        return 0;
    }
    return process(array, 0, array - 1);
}
function process(array, L, R) {
    if (L = R) {
        return 0;
    }
    var mid = L + ((R - L) >> 1);
    return process(array, L, mid) + process(array, mid + 1, R) + merge(array, L, mid, R)
}
function merge(array, L, m, R) {
    var help = [];
    var p1 = L;
    var p2 = m + 1;
    var res = 0;
    while (p1 <= m && p2 <= R) {
        res += array[p1] < array[p2] ? (R - p2 + 1) * array[p1] : 0;
        help[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
    }
    while (p1 <= m) {
        help[i++] = array[p1++];
    }
    while (p2 <= R) {
        help[i++] = array[p2++];
    }
    for (var i = 0; i < help.length; i++) {
        array[L + i] = help[i];
    }
    return res;
}

  1. 堆结构就是用数组实现的完全二叉树结构
  2. 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
  3. 完全二叉树中如果每棵子树的最小值都在顶部就是小根堆

堆排序

  1. 先让整个数组都变成大根堆结构,建立堆的过程:
    1. 从上到下的方法,时间复杂度为O(N*logN)
    2. 从下到上的方法,时间复杂度为O(N)

2,把堆的最大值和堆末尾的值交换,然后减少堆的大小之后,再去调整堆,一直周而复始,时间复杂度为O(N*logN)
3,堆的大小减小成0之后,排序完成
算法如下:

function heapSort(array) {
    if (array = null || array.length < 2) {
        return;
    }
    for (var i = 0; i < array.length; i++) {
        heapInsert(array, i);
    }
    var heapSize = array.length;
    swap(array, 0, --heapSize);
    while (heapSize > 0) {
        heapify(array, 0, heapSize);
        swap(array, 0, --heapSize);
    }
}
// 某个数现在处在index位置,往上继续移动
function heapInsert(array, index) {
    while (array[index] > array[(index - 1) / 2]) {
        swap(array, index, (index - 1) / 2);
        index = (index - 1) / 2;
    }
}
// 某个数在index位置,能否往下移动
function heapify(array, index, heapSize) {
    var left = index * 2 + 1; //左孩子下标
    while (left < heapSize) { //下方还有孩子的时候
        // 两个孩子中,谁的值大,把下标给largest
        var largest = left + 1 < heapSize && array[left + 1] > array[left] ? left + 1 : left;
        // 父和较大的孩子之间,谁的值大,把下标给largest
        largest = array[largest] > array[index] ? largest : index;
        if (largest == index) {
            break;
        }
        swap(array, largest, index);
        index = largest;
        left = index * 2 + 1;
    }
}
function swap(array, i, j) {
    var tmp = array[i];
    array[i] = array[j];
    array[j] = tmp;
}

maxHeap

解析:首先用heapInsert方法将数组转换成大根堆形式,然后将堆的第一个值也就是数组的最大值与堆最后一个互换,然后重新对数组转换为大根堆形式,不过此时对于堆最后一个值不参与转换,这样就相当于将数组最大值固定在数组末端,在下一次大根堆转换后,同样将第一个值与此时的最末值交换,再继续转换,此时就能得到数组第二大的值,并且储存在数组倒数第二个位置,一直进行这个过程,最后当heapSize为0时停止。

堆排序扩展题目

已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
先在npm搜索优先级队列的JS代码,直接下载应用

<script src="./node_modules/js-priority-queue/priority-queue.min.js"></script>

接下来展示代码,其中return a-b 表示输出由小到大队列

var queue = new PriorityQueue({ comparator: function (a, b) { return a - b; } });
function SortArrayDistanceLseeK(array, k) {
    if (array == null && array.length < 2) {
        return;
    }
    var index = 0;
    for (; index <= Math.min(array.length, k); index++) {
        queue.queue(array[index]);
    }
    var i = 0
    for (; index < array.length; i++, index++) {
        array[i] = queue.dequeue();
        queue.queue(array[index]);
    }
    for (; i < array.length; i++) {
        array[i] = queue.dequeue();
    }
}

首先判断数组长度是否小于所提供的k值,如果小于,则能直接输出队列,若大于k值,则继续进行,将队列进行排序后,输出队列中的最小值,然后将数组中后面的一个数添加到队列中进行排序,由于队列长度是k,所以能保证元素移动距离不超过k,进行到最后队列中剩下数组最后k个元素且已经排好序,然后将元素按顺序输出,这样就能将原数组排好序,且每个元素移动距离不超过k。

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