排序算法 JavaScript

一、冒泡排序

算法引见:

  1. 比较相邻的两个元素,如果前一个比后一个大,则交流位置。
  2. 第一轮把最大的元素放到了末了面。
  3. 由于每次排序末了一个都是最大的,所以以后依据步骤1排序末了一个元素不必比较。
function bubble_sort(arr){
  var swap;  
  for(var i=0;i<arr.length-1;i++){
    for(var j=0;j<arr.length-i-1;j++){
      if(arr[j]>arr[j+1]){
        swap=arr[j];
        arr[j]=arr[j+1];
        arr[j+1]=swap;
      }
    }
  }
}

冒泡算法革新:

  1. 设置一个标志,如果这一趟发作了交流,则为true。否则为false。如果这一趟没有发作交流,则申明排序已完成。代码以下:
function bubble_sort_1(arr) {
  var n = arr.length,
  flag = true,
  swap;
  while(flag){
    flag = false;
    for(var j = 1; j<n; j++){
      if(arr[j - 1]>arr[j]) {
        swap = arr[j-1];
        arr[j-1] = arr[j];
        arr[j] = swap;
       flag = true;
      }0
    }
    n --;  
  }
  return arr;
}
  1. 如果数组长度是20,如果只需前十位是无序分列的,后十位是有序且都大于前十位,所以第一趟遍历排序的时刻发作交流的位置肯定小于10,且该位置以后的肯定有序,我们只须要排序好该位置之前的就可以,因而我们要来标记这个位置就可以了,即可以纪录每次扫描中末了一次交流的位置,下次扫描的时刻只需扫描到上次的末了交流位置就好了,由于背面的都是已排好序的,无需再比较,代码以下:
function bubble_sort_2(arr) {
  var n=arr.length;
  var j,k;  
  var flag=n;
  var swap;
  while(flag>0) {  
    k=flag;  
    flag=0;  
    for(j=1;j<k;j++){ 
        if (arr[j - 1] > arr[j])  
        {  
            swap=arr[j-1];
            arr[j-1]=arr[j];
            arr[j]=swap;
            flag=j;  
        }  
    }  
  } 

}
  1. 每一次轮回从两端动身算出最大和最小值,代码以下:
function bubble_sort_3(arr) {
  var low = 0;
  var high= arr.length-1; //设置变量的初始值
  var swap,j;
  while (low < high) {
    for (j= low; j< high; ++j) {         //正向冒泡,找到最大者
      if (arr[j]> arr[j+1]) {
        swap = arr[j]; arr[j]=arr[j+1];arr[j+1]=swap;
      }
    }
    --high;  //修正high值, 前移一名
    for (j=high; j>low; --j) {          //反向冒泡,找到最小者
      if (arr[j]<arr[j-1]) {
        swap = arr[j]; arr[j]=arr[j-1];arr[j-1]=swap;
      }
    } 
    ++low;  //修正low值,后移一名
  }
  return arr;
}
  1. 在代码3的基础上纪录每次扫描末了一次交流的位置,下次扫描的时刻只需扫描到上次的末了交流位置就行,同代码2,代码以下:
function bubble_sort_3(arr) {
  var low = 0;
  var high= arr.length-1; //设置变量的初始值
  var swap,j;
  while (low < high) {
    var pos1 = 0,pos2=0; 
    for (let i= low; i< high; ++i) { //正向冒泡,找到最大者
      if (arr[i]> arr[i+1]) {
        swap = arr[i]; arr[i]=arr[i+1];arr[i+1]=swap;
        pos1 = i ;
      }
    }

    high = pos1;// 纪录上次位置

    for (let j=high; j>low; --j) { //反向冒泡,找到最小者
      if (arr[j]<arr[j-1]) {
        swap = arr[j]; arr[j]=arr[j-1];arr[j-1]=swap;  
        pos2 = j;
      }
    }   
    
    low = pos2; //修正low值
  }
  return arr;
}

冒泡排序动图演示:
《排序算法 JavaScript》

二、疾速排序

算法引见:

疾速排序是对冒泡排序的一种革新,第一趟排序时将数据分红两部份,一部份比另一部份的一切数据都要小。然后递归挪用,在双方都执行疾速排序。

function quick_sort(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 quick_sort(left).concat([pivot],quick_sort(right));
}

疾速排序动图演示:
《排序算法 JavaScript》

三、挑选排序

算法引见:

挑选排序就是从一个未知数据空间里,拔取之最放到一个新的空间

代码以下:

function selection_sort(arr) {
  var len = arr.length;
  var minIndex, swap;
  for (var i = 0; i < len - 1; i++) {
    minIndex = i;
    for (var j = i + 1; j < len; j++) {
      if (arr[j] < arr[minIndex]) { //寻觅最小的数
        minIndex = j; //将最小数的索引保留
      }
    }
    swap = arr[i];
    arr[i] = arr[minIndex];
    arr[minIndex] = swap;
  }
  return arr;
}

挑选排序动图演示:
《排序算法 JavaScript》

四、插入排序

算法引见:

  1. 从第一个默许被排好序的元素最先
  2. 掏出下一个元素,在已排序的元素序列中从后向前扫描
  3. 如果已排序的元素大于掏出的元素,则将其离别向后挪动一名
  4. 直到找到已排序的元素中小于或即是掏出的元素,将掏出的元素放到它的后一名
  5. 反复步骤2

代码以下:

function insertion_sort(arr) {
  for (var i = 1; i < arr.length; i++) {
    var key = arr[i];
    var j = i - 1;
    while ( arr[j] > key) {
      arr[j + 1] = arr[j];
         j--;
    }
    arr[j + 1] = key;
  }
  return arr;
}

插入排序算法革新-二分法插入排序:

function binaryInsertion_sort(arr) {
  for (var i = 1; i < arr.length; i++) {
    var key = arr[i], left = 0, right = i - 1;
    while (left <= right) {
      var middle = parseInt((left + right) / 2);
      if (key < arr[middle]) {
        right = middle - 1;
      } else {
        left = middle + 1;
      }
    }
    for (var j = i - 1; j >= left; j--) {
      arr[j + 1] = arr[j];
    }
    arr[left] = key;
  }
  return arr;
}

插入排序法动图演示:
《排序算法 JavaScript》

五、希尔排序

算法引见:

希尔排序是冒泡排序的一种更高效力的完成。它与冒泡排序的不同之处在于,它会优先比较距离较远的元素。希尔排序的中心在于距离序列的设定。

《排序算法 JavaScript》

上图中先每差5为一组举行比较,以后再每差2为一组惊醒比较,末了就是两两比较。代码以下:

function shell_sort(arr) {
  var len = arr.length,
  temp,
  gap = 1;
  while(gap < len/5) { //动态定义距离序列
    gap =gap*5+1;
  }
  for (gap; gap > 0; gap = Math.floor(gap/5)) {
    for (var i = gap; i < len; i++) {
      temp = arr[i];
      for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
        arr[j+gap] = arr[j];
      }
      arr[j+gap] = temp;
    }
  }
  return arr;
}

六、合并排序

算法引见:

作为一种典范的分而治之头脑的算法运用,合并排序的完成由两种要领:

  • 自上而下的递归(一切递归的要领都可以用迭代重写,所以就有了第2种要领)
  • 自下而上的迭代

代码以下:

function merge_sort(arr) {  //采纳自上而下的递归要领
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
    var result = [];
 
    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }
 
    while (left.length)
        result.push(left.shift());
 
    while (right.length)
        result.push(right.shift());
 
    return result;
}

合并排序动图演示 :
《排序算法 JavaScript》

七、堆排序

起首邃晓什么是堆,堆实在可以这么明白,相似金字塔,一层有一个元素,两层有两个元素,三层有四个元素,每层从数组中取元素,从左到右的递次放到堆响应的位置上,也就是说每一层元素个数为2n-1 ;(n 代表行数),这就完成了建堆。

堆排序可以说是一种应用堆的观点来排序的挑选排序。分为两种要领:

  • 大顶堆:每一个节点的值都大于或即是其子节点的值,在堆排序算法中用于升序分列
  • 小顶堆:每一个节点的值都小于或即是其子节点的值,在堆排序算法中用于降序分列

代码以下:

var len;    //由于声明的多个函数都须要数据长度,所以把len设置成为全局变量

function buildMaxHeap(arr) {   //竖立大顶堆
    len = arr.length;
    for (var i = Math.floor(len/2); i >= 0; i--) {
        heapify(arr, i);
    }
}

function heapify(arr, i) {     //堆调解
    var left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[left] > arr[largest]) {
        largest = left;
    }

    if (right < len && arr[right] > arr[largest]) {
        largest = right;
    }

    if (largest != i) {
        swap(arr, i, largest);
        heapify(arr, largest);
    }
}

function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

function heapSort(arr) {
    buildMaxHeap(arr);

    for (var i = arr.length-1; i > 0; i--) {
        swap(arr, 0, i);
        len--;
        heapify(arr, 0);
    }
    return arr;
}

堆排序动图演示:
《排序算法 JavaScript》

八、计数排序

算法引见:

计数排序的中心在于将输入的数据值转化为键存储在分外拓荒的数组空间中。

作为一种线性时候复杂度的排序,计数排序请求输入的数据必需是有肯定局限的整数。

代码以下:

function counting_sort(arr, maxValue) {
    var bucket = new Array(maxValue+1),
        sortedIndex = 0;
        arrLen = arr.length,
        bucketLen = maxValue + 1;

    for (var i = 0; i < arrLen; i++) {
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }

    for (var j = 0; j < bucketLen; j++) {
        while(bucket[j] > 0) {
            arr[sortedIndex++] = j;
            bucket[j]--;
        }
    }

    return arr;
}

计数排序动图演示:
《排序算法 JavaScript》

九、桶排序

桶排序是计数排序的升级版。它应用了函数的映照关联,高效与否的症结就在于这个映照函数的肯定。
为了使桶排序越发高效,我们须要做到这两点:

在分外空间足够的情况下,只管增大桶的数目

运用的映照函数可以将输入的N个数据匀称的分派到K个桶中

同时,关于桶中元素的排序,挑选何种比较排序算法关于机能的影响至关重要。

什么时刻最快(Best Cases):

  • 当输入的数据可以匀称的分派到每一个桶中

什么时刻最慢(Worst Cases):

  • 当输入的数据被分派到了同一个桶中

代码演示:

function bucketSort(arr, bucketSize) {
    if (arr.length === 0) {
      return arr;
    }

    var i;
    var minValue = arr[0];
    var maxValue = arr[0];
    for (i = 1; i < arr.length; i++) {
      if (arr[i] < minValue) {
          minValue = arr[i];                //输入数据的最小值
      } else if (arr[i] > maxValue) {
          maxValue = arr[i];                //输入数据的最大值
      }
    }

    //桶的初始化
    var DEFAULT_BUCKET_SIZE = 5;            //设置桶的默许数目为5
    bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
    var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;   
    var buckets = new Array(bucketCount);
    for (i = 0; i < buckets.length; i++) {
        buckets[i] = [];
    }

    //应用映照函数将数据分派到各个桶中
    for (i = 0; i < arr.length; i++) {
        buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
    }

    arr.length = 0;
    for (i = 0; i < buckets.length; i++) {
        insertionSort(buckets[i]);                      //对每一个桶举行排序,这里运用了插入排序
        for (var j = 0; j < buckets[i].length; j++) {
            arr.push(buckets[i][j]);                      
        }
    }

    return arr;
}

十、基数排序

基数排序须知:

基数排序有两种要领:

  • MSD 从高位最先举行排序
  • LSD 从低位最先举行排序

基数排序 vs 计数排序 vs 桶排序:

这三种排序算法都应用了桶的观点,但对桶的运用要领上有显著差别:

  • 基数排序:依据键值的每位数字来分派桶
  • 计数排序:每一个桶只存储单一键值
  • 桶排序:每一个桶存储肯定局限的数值

代码演示:

function radix_sort(arr, maxDigit) {
  var mod = 10;
  var dev = 1;
  var counter = [];
  for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
    for(var j = 0; j < arr.length; j++) {
      var bucket = parseInt((arr[j] % mod) / dev);
      if(counter[bucket]== null) {
        counter[bucket] = [];
      }
    counter[bucket].push(arr[j]);
    }
    var pos = 0;
    for(var j = 0; j < counter.length; j++) {
      var value = null;
      if(counter[j]!=null) {
        while ((value = counter[j].shift()) != null) {
          arr[pos++] = value;
        }
      }
    }
  }
  return arr;
}

基数排序动图演示:
《排序算法 JavaScript》

《排序算法 JavaScript》

参考:https://www.cnblogs.com/liyon…

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