经常使用排序算法之JavaScript完成

资助我以写出更好的文章,give me a cup of coffee?

1、插进去排序

1)算法简介

插进去排序(Insertion-Sort)的算法形貌是一种简朴直观的排序算法。它的事情道理是经过历程构建有序序列,关于未排序数据,在已排序序列中从后向前扫描,找到响应位置并插进去。插进去排序在完成上,一般采纳in-place排序(即只需用到O(1)的分外空间的排序),因而在从后向前扫描历程当中,须要反复把已排序元素逐渐向后挪位,为最新元素供应插进去空间。

2)算法形貌和完成

一般来说,插进去排序都采纳in-place在数组上完成。详细算法形貌以下:

从第一个元素最先,该元素能够以为已被排序;
掏出下一个元素,在已排序的元素序列中从后向前扫描;
假如该元素(已排序)大于新元素,将该元素移到下一位置;
反复步骤3,直到找到已排序的元素小于或许即是新元素的位置;
将新元素插进去到该位置后;
反复步骤2~5。

JavaScript代码完成:


function insertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        for (var i = 1; i < array.length; i++) {
            var key = array[i];
            var j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
        return array;
    } else {
        return 'array is not an Array!';
    }
}

3)算法剖析

最好状况:输入数组按升序分列。T(n) = O(n)
最坏状况:输入数组按降序分列。T(n) = O(n2)
均匀状况:T(n) = O(n2)

二、二分插进去排序

1)算法简介

二分插进去(Binary-insert-sort)排序是一种在直接插进去排序算法上举行小修改的排序算法。其与直接插进去排序算法最大的辨别在于查找插进去位置时运用的是二分查找的体式格局,在速率上有肯定提拔。

2)算法形貌和完成

一般来说,插进去排序都采纳in-place在数组上完成。详细算法形貌以下:

从第一个元素最先,该元素能够以为已被排序;
掏出下一个元素,在已排序的元素序列中二分查找到第一个比它大的数的位置;
将新元素插进去到该位置后;
反复上述两步。

JavaScript代码完成:


function binaryInsertionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        for (var i = 1; i < array.length; i++) {
            var key = array[i], left = 0, right = i - 1;
            while (left <= right) {
                var middle = parseInt((left + right) / 2);
                if (key < array[middle]) {
                    right = middle - 1;
                } else {
                    left = middle + 1;
                }
            }
            for (var j = i - 1; j >= left; j--) {
                array[j + 1] = array[j];
            }
            array[left] = key;
        }
        return array;
    } else {
        return 'array is not an Array!';
    }
}

3)算法剖析

最好状况:T(n) = O(nlogn)
最差状况:T(n) = O(n2)
均匀状况:T(n) = O(n2)

三、挑选排序

1)算法简介

挑选排序(Selection-sort)是一种简朴直观的排序算法。它的事情道理:首先在未排序序列中找到最小(大)元素,存放到排序序列的肇端位置,然后,再从盈余未排序元素中继承寻觅最小(大)元素,然后放到已排序序列的末端。以此类推,直到一切元素均排序终了。

2)算法形貌和完成

n个纪录的直接挑选排序可经过n-1趟直接挑选排序获得有序效果。详细算法形貌以下:

初始状况:无序区为R[1..n],有序区为空;
第i趟排序(i=1,2,3…n-1)最先时,当前有序区和无序辨别别为R[1..i-1]和R(i..n)。该趟排序从当前无序区当选出关键字最小的纪录 R[k],将它与无序区的第1个纪录R交流,使R[1..i]和R[i+1..n)离别变成纪录个数增添1个的新有序区和纪录个数削减1个的新无序区;
n-1趟完毕,数组有序化了。

JavaScript代码完成:

function selectionSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        var len = array.length, temp;
        for (var i = 0; i < len - 1; i++) {
            var min = array[i];
            for (var j = i + 1; j < len; j++) {
                if (array[j] < min) {
                    temp = min;
                    min = array[j];
                    array[j] = temp;
                }
            }
            array[i] = min;
        }
        return array;
    } else {
        return 'array is not an Array!';
    }
}

3)算法剖析

最好状况:T(n) = O(n2)
最差状况:T(n) = O(n2)
均匀状况:T(n) = O(n2)

四、冒泡排序

1)算法简介

冒泡排序是一种简朴的排序算法。它反复地访问过要排序的数列,一次比较两个元素,假如它们的递次毛病就把它们交流过来。访问数列的事情是反复地举行直到没有再须要交流,也就是说该数列已排序完成。这个算法的名字由来是由于越小的元素会经过交流逐步“浮”到数列的顶端。

2)算法形貌和完成

详细算法形貌以下:

比较相邻的元素。假如第一个比第二个大,就交流它们两个;
对每一对相邻元素作一样的事情,从最先第一对到末端的末了一对,如许在末了的元素应当会是最大的数;
针对一切的元素反复以上的步骤,除了末了一个;
反复步骤1~3,直到排序完成。

JavaScript代码完成:


function bubbleSort(arr){
    //外层轮回,共要举行arr.length次求最大值操纵
    for(var i=0;i<arr.length;i++){
        //内层轮回,找到第i大的元素,并将其和第i个元素交流
        for(var j=i;j<arr.length;j++){
            if(arr[i]<arr[j]){
                //交流两个元素的位置
                var temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }
    }
}

五、疾速排序

1)算法简介

疾速排序的基本思想:经过历程一趟排序将待排纪录分隔成自力的两部份,个中一部份纪录的关键字均比另一部份的关键字小,则可离别对这两部份纪录继承举行排序,以到达全部序列有序。

2)算法形貌和完成

疾速排序运用分治法来把一个串(list)分为两个子串(sub-lists)。详细算法形貌以下:

从数列中挑出一个元素,称为 "基准"(pivot);
从新排序数列,一切元素比基准值小的摆放在基准前面,一切元素比基准值大的摆在基准的背面(雷同的数能够就任一边)。在这个分区退出以后,该基准就处于数列的中心位置。这个称为分区(partition)操纵;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

JavaScript代码完成:

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));

};

六、堆排序

1)算法简介

堆排序(Heapsort)是指运用堆这类数据构造所设想的一种排序算法。聚集是一个近似完整二叉树的构造,并同时满足聚集的性子:即子结点的键值或索引老是小于(或许大于)它的父节点。

2)算法形貌和完成

详细算法形貌以下:

将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
将堆顶元素R[1]与末了一个元素R[n]交流,此时获得新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
由于交流后新的堆顶R[1]能够违背堆的性子,因而须要对当前无序区(R1,R2,......Rn-1)调解为新堆,然后再次将R[1]与无序区末了一个元素交流,获得新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不停反复此历程直到有序区的元素个数为n-1,则全部排序历程完成。

JavaScript代码完成:


/*要领申明:堆排序
@param  array 待排序数组*/           
function heapSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        //建堆
        var heapSize = array.length, temp;
        for (var i = Math.floor(heapSize / 2); i >= 0; i--) {
            heapify(array, i, heapSize);
        }
 
        //堆排序
        for (var j = heapSize - 1; j >= 1; j--) {
            temp = array[0];
            array[0] = array[j];
            array[j] = temp;
            heapify(array, 0, --heapSize);
        }
    } else {
        return 'array is not an Array!';
    }
}
/*要领申明:保护堆的性子
@param  arr 数组
@param  x   数组下标
@param  len 堆大小*/
function heapify(arr, x, len) {
    if (Object.prototype.toString.call(arr).slice(8, -1) === 'Array' && typeof x === 'number') {
        var l = 2 * x, r = 2 * x + 1, largest = x, temp;
        if (l < len && arr[l] > arr[largest]) {
            largest = l;
        }
        if (r < len && arr[r] > arr[largest]) {
            largest = r;
        }
        if (largest != x) {
            temp = arr[x];
            arr[x] = arr[largest];
            arr[largest] = temp;
            heapify(arr, largest, len);
        }
    } else {
        return 'arr is not an Array or x is not a number!';
    }
}

3)算法剖析

最好状况:T(n) = O(nlogn)
最差状况:T(n) = O(nlogn)
均匀状况:T(n) = O(nlogn)

七、兼并排序

1)算法简介

兼并排序是建立在兼并操纵上的一种有用的排序算法。该算法是采纳分治法(Divide and Conquer)的一个异常典范的运用。兼并排序是一种稳固的排序要领。将已有序的子序列兼并,获得完整有序的序列;即先使每一个子序列有序,再使子序列段间有序。若将两个有序表兼并成一个有序表,称为2-路兼并。

2)算法形貌和完成

详细算法形貌以下:

把长度为n的输入序列分红两个长度为n/2的子序列;
对这两个子序列离别采纳兼并排序;
将两个排序好的子序列兼并成一个终究的排序序列。

JavaScript代码完成:


function mergeSort(array, p, r) {
    if (p < r) {
        var q = Math.floor((p + r) / 2);
        mergeSort(array, p, q);
        mergeSort(array, q + 1, r);
        merge(array, p, q, r);
    }
}
function merge(array, p, q, r) {
    var n1 = q - p + 1, n2 = r - q, left = [], right = [], m = n = 0;
    for (var i = 0; i < n1; i++) {
        left[i] = array[p + i];
    }
    for (var j = 0; j < n2; j++) {
        right[j] = array[q + 1 + j];
    }
    left[n1] = right[n2] = Number.MAX_VALUE;
    for (var k = p; k <= r; k++) {
        if (left[m] <= right[n]) {
            array[k] = left[m];
            m++;
        } else {
            array[k] = right[n];
            n++;
        }
    }
}

3)算法剖析

最好状况:T(n) = O(n)
最差状况:T(n) = O(nlogn)
均匀状况:T(n) = O(nlogn)

八、桶排序

1)算法简介

桶排序 (Bucket sort)的事情的道理:假定输入数据恪守均匀分布,将数据分到有限数目的桶里,每一个桶再离别排序(有能够再运用别的排序算法或是以递归体式格局继承运用桶排序举行排序)。

2)算法形貌和完成

详细算法形貌以下:

设置一个定量的数组看成空桶;
遍历输入数据,而且把数据一个一个放到对应的桶里去;
对每一个不是空的桶举行排序;
从不是空的桶里把排好序的数据拼接起来。

JavaScript代码完成:


/*要领申明:桶排序
@param  array 数组
@param  num   桶的数目*/
function bucketSort(array, num) {
    if (array.length <= 1) {
        return array;
    }
    var len = array.length, buckets = [], result = [], min = max = array[0], regex = '/^[1-9]+[0-9]*$/', space, n = 0;
    num = num || ((num > 1 && regex.test(num)) ? num : 10);
    for (var i = 1; i < len; i++) {
        min = min <= array[i] ? min : array[i];
        max = max >= array[i] ? max : array[i];
    }
    space = (max - min + 1) / num;
    for (var j = 0; j < len; j++) {
        var index = Math.floor((array[j] - min) / space);
        if (buckets[index]) {   //  非空桶,插进去排序
            var k = buckets[index].length - 1;
            while (k >= 0 && buckets[index][k] > array[j]) {
                buckets[index][k + 1] = buckets[index][k];
                k--;
            }
            buckets[index][k + 1] = array[j];
        } else {    //空桶,初始化
            buckets[index] = [];
            buckets[index].push(array[j]);
        }
    }
    while (n < num) {
        result = result.concat(buckets[n]);
        n++;
    }
    return result;
}

3)算法剖析

桶排序最好状况下运用线性时候O(n),桶排序的时候复杂度,取决与对各个桶之间数据举行排序的时候复杂度,由于别的部份的时候复杂度都为O(n)。很显然,桶分别的越小,各个桶之间的数据越少,排序所用的时候也会越少。但响应的空间斲丧就会增大。

九、计数排序

1)算法简介

计数排序(Counting sort)是一种稳固的排序算法。计数排序运用一个分外的数组C,个中第i个元素是待排序数组A中值即是i的元素的个数。然后依据数组C来将A中的元素排到准确的位置。它只能对整数举行排序。

2)算法形貌和完成

详细算法形貌以下:

找出待排序的数组中最大和最小的元素;
统计数组中每一个值为i的元素涌现的次数,存入数组C的第i项;
对一切的计数累加(从C中的第一个元素最先,每一项和前一项相加);
反向添补目的数组:将每一个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

JavaScript代码完成:


function countingSort(array) {
    var len = array.length, B = [], C = [], min = max = array[0];
    for (var i = 0; i < len; i++) {
        min = min <= array[i] ? min : array[i];
        max = max >= array[i] ? max : array[i];
        C[array[i]] = C[array[i]] ? C[array[i]] + 1 : 1;
    }
    for (var j = min; j < max; j++) {
        C[j + 1] = (C[j + 1] || 0) + (C[j] || 0);
    }
    for (var k = len - 1; k >=0; k--) {
        B[C[array[k]] - 1] = array[k];
        C[array[k]]--;
    }
    return B;
}

3)算法剖析

当输入的元素是n 个0到k之间的整数时,它的运转时候是 O(n + k)。计数排序不是比较排序,排序的速率快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的局限(即是待排序数组的最大值与最小值的差加上1),这使得计数排序关于数据局限很大的数组,须要大批时候和内存。

文章泉源:http://blog.jobbole.com/76339/

    原文作者:trigkit4
    原文地址: https://segmentfault.com/a/1190000000656344
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞