Javascript 数组自定义排序,并获取排序后的保存原索引的同位数组(堆排序实现)

Posted 绣春刀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javascript 数组自定义排序,并获取排序后的保存原索引的同位数组(堆排序实现)相关的知识,希望对你有一定的参考价值。

比如数组A:

[

0: 5,

1: 2,

2: 4,

3: 3,

4: 1

]

排序后的结果为:[1, 2, 3, 4, 5],但是有时候会有需求想要保留排序前的位置到一个同位数组里,如前例则为:[4, 1, 3, 2, 0],因此就利用堆排序写了一个单独的数组排序过程加以实现。

代码如下:

    function arrayKeys(arr) {
        var i    = 0, 
            len  = arr.length,
            keys = [];
        while (i < len) {
            keys.push(i++);
        }
        return keys;
    }   
// 判断变量是否为数组 function isArray(arr) { return ({}).toString.call(arr).match(/^\[[^\s]+\s*([^\s]+)\]$/)[1] == ‘Array‘; }
// 堆排序
function heapSort(arr, keys, order) { if (!isArray(arr) || !isArray(keys)) return ; var order = (order + ‘‘).toLowerCase() == ‘desc‘ ? order : ‘asc‘; // 交换位置 function changePos(arr, cur, left) { var tmp; tmp = arr[cur]; arr[cur] = arr[left]; arr[left] = tmp; } // 构造二叉堆 function heap(arr, start, end, isMax) { var isMax = isMax == undefined ? true : isMax, // 是否最大堆,否为最小堆 cur = start, // 当前节点的位置 left = 2 * cur + 1; // 左孩子的位置 for (; left <= end; cur = left, left = 2 * left + 1) { // left是左孩子,left + 1是右孩子 if (left < end && ((isMax && arr[left] < arr[left + 1]) || (!isMax && arr[left] > arr[left + 1]))) { left++; // 左右子节点中取较大/小者 } if ((isMax && arr[cur] >= arr[left]) || (!isMax && arr[cur] <= arr[left])) { break; } else { // 原index跟随排序同步进行 changePos(keys, cur, left); changePos(arr, cur, left); } } } return +function () { // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个二叉堆 for (var len = arr.length, i = Math.floor(len / 2) - 1; i >= 0; i--) { heap(arr, i, len - 1, order == ‘asc‘); } // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素 for (i = len - 1; i > 0; i--) { changePos(keys, 0, i); changePos(arr, 0, i); // 调整arr[0...i - 1],使得arr[0...i - 1]仍然是一个最大/小堆 // 即,保证arr[i - 1]是arr[0...i - 1]中的最大/小值 heap(arr, 0, i - 1, order == ‘asc‘); } }(); }
// 测试
var aa = [5, 2, 8, 9, 1, 3, 4, 7, 6]; var kk = arrayKeys(aa); heapSort(aa, kk, ‘asc‘); console.log(aa); // 排序后:[1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(kk); // 原索引:[4, 1, 5, 6, 0, 8, 7, 2, 3]

当然,也可以在确保安全的前提下把该方法写入Array.prototype.heapSort,这样就可以用数组直接调用了,代码略微修改一下即可,如下:

    Array.prototype._heapSort = function (keys, order) {
        var arr   = this,
            keys  = ({}).toString.call(keys) == ‘[object Array]‘ ? keys : [],
            order = (order + ‘‘).toLowerCase() == ‘desc‘ ? order : ‘asc‘;
        // 交换位置
        function changePos(arr, cur, left) {
            var tmp;
            tmp       = arr[cur];
            arr[cur]  = arr[left];
            arr[left] = tmp;
        }
        // 构造二叉堆
        function heap(arr, start, end, isMax) {
            var isMax = isMax == undefined ? true : isMax,  // 是否最大堆,否为最小堆
                cur   = start,        // 当前节点的位置
                left  = 2 * cur + 1;  // 左孩子的位置
            for (; left <= end; cur = left, left = 2 * left + 1) {
                // left是左孩子,left + 1是右孩子
                if (left < end && ((isMax && arr[left] < arr[left + 1]) || (!isMax && arr[left] > arr[left + 1]))) {
                    left++;  // 左右子节点中取较大/小者
                }
                if ((isMax && arr[cur] >= arr[left]) || (!isMax && arr[cur] <= arr[left])) {
                    break;
                } else {
                    // 原index跟随排序同步进行
                    changePos(keys, cur, left);
                    changePos(arr, cur, left);
                }
            }
        }
        return +function () {
            // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个二叉堆
            for (var len = arr.length, i = Math.floor(len / 2) - 1; i >= 0; i--) {
                heap(arr, i, len - 1, order == ‘asc‘);
            }
            // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
            for (i = len - 1; i > 0; i--) {
                changePos(keys, 0, i);
                changePos(arr, 0, i);
                // 调整arr[0...i - 1],使得arr[0...i - 1]仍然是一个最大/小堆
                // 即,保证arr[i - 1]是arr[0...i - 1]中的最大/小值
                heap(arr, 0, i - 1, order == ‘asc‘);
            }
        }();
    };

 

以上是关于Javascript 数组自定义排序,并获取排序后的保存原索引的同位数组(堆排序实现)的主要内容,如果未能解决你的问题,请参考以下文章

如何按自定义顺序对 JavaScript 中的数组进行排序? [复制]

如何在javascript中定义自定义排序功能?

31Arrays数组排序(续)——自定义排序

javascript 常见数组操作( 1数组整体元素修改 2 数组筛选 3jquery 元素转数组 4获取两个数组中相同部分或者不同部分 5数组去重并倒序排序 6数组排序 7

Java 数组排序:获取数组索引的排序列表的快速方法

JavaScript数字数组怎么按数字大小排序?