最常用的五种排序算法

415 阅读3分钟

排序算法是平时开发和工作中经常遇到的,今天为大家总结了五种最常用的排序算法,每一种算法都附带一张排序过程的动图,让大家更加直观的了解排序算法实现思想。

数据交换的公共方法

function swap(arr,index1,index2) {
    let temp=arr[index1];
    arr[index1]=arr[index2];
    arr[index2]=temp;
}
let list=[12,45,1,45,32,15,41,21,56,23,65,45,12,36,21,2,3,2222,2,1];

冒泡排序(Bubble Sort)

冒泡排序算法,它是最慢的排序算法之一,但也是一种容易实现的排序算法。比较相邻的数据

动图封面

function maopao(list){
  let len=list.length;
  for(let i=0;i<len;i++){          //控制循环的次数
    for(let j=0;j<len-i-1;j++){    //控制每次循环比较的次数
      if(list[j]>list[j+1]){
        swap(list,j,j+1)
      }
    }
  }
  return list
}

选择排序(Selection Sort)

选择排序从数组的开头开始,将第一个元素和其他元素进行比较。检查完所有元素后,最小的元素会被放到数组第一位置,然后算法会从第二的位置继续。一直进行,当进行到数组的倒数第二个位置时,所有的数据便会完成排序
在时间复杂度上表现最稳定的排序算法之一,因为无论什么数据进去都是O(n²)的时间复杂度。。。所以用到它的时候,数据规模越小越好

动图封面

function selectionSort(list) {      //选择排序
  let min;
  for(let i=0;i<list.length-1;i++){     //控制循环的次数
      min=i;
      for(let j=i+1;j<list.length;j++){  //控制每次循环比较的次数
          if(list[j]<list[min]){   //寻找最小的数
              min=j;               //将最小数的索引保存
          }
      }
      swap(list,i,min);
  }
  return list
}

归并排序(Merge Sort)

作为一种典型的分而治之思想的算法应用,归并排序的实现有两种方法:

  1. 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第2种方法)
  2. 自下而上的迭代

动图封面

function mergeSort(arr) {  //采用自上而下的递归方法
    let len = arr.length;
    if(len < 2) {
        return arr;
    }
    let middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
    let result = [];
    while (left.length>0 && right.length>0) {
        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;
}
console.log(mergeSort(list));

快速排序(Quick Sort)

又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高! 它是处理大数据最快的排序算法之一了。虽然Worst Case的时间复杂度达到了O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为O(n log n) 的排序算法表现要更好
快速排序的最坏运行情况是O(n²),比如说顺序数列的快排。但它的平摊期望时间是O(n log n) ,且O(n log n)记号中隐含的常数因子很小,比复杂度稳定等于O(n log n)的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序

function quickSort(arr, left, right) {
    var len = arr.length,
        partitionIndex,
        left = typeof left != 'number' ? 0 : left,
        right = typeof right != 'number' ? len - 1 : right;

    if (left < right) {
        partitionIndex = partition(arr, left, right);
        quickSort(arr, left, partitionIndex-1);
        quickSort(arr, partitionIndex+1, right);
    }
    return arr;
}
function partition(arr, left ,right) {     //分区操作
    var pivot = left,                      //设定基准值(pivot)
        index = pivot + 1;
    for (var i = index; i <= right; i++) {
        if (arr[i] < arr[pivot]) {
            swap(arr, i, index);
            index++;
        }
    }
    swap(arr, pivot, index - 1);
    return index-1;
}
console.log(quickSort(list));

堆排序(Heap Sort)

堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列

动图封面

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

❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创作更好的文章

关注公众号_前端码头_,获取独家学习路线+博主私人微信,更多前端小干货等着你喔