6种常用排序算法的实现和比较

闲来无事,写了6种常见的排序算法,记录下随笔;

1、冒泡排序

交换排序,相邻两个数对比,小的往前移动,就像泡泡一样。时间复杂度O(n^2),稳定。

const bubble_sort = function(arr){
    const {length} = arr;
    for(let i = length - 1; i > 0; i --){      
      for(let j = length - 1; j >= 0; j -- ){
        if(arr[j] < arr[j-1])
          [arr[j-1], arr[j]] = [arr[j], arr[j-1]]       
      }
    }
    return arr;
 }

2、插入排序

设定第一个数值为有序序列,从第二个数值开始,依次取值插入到有序序列里合适的位置,最终得到排序结果,时间复杂度O(n^2),稳定。

const insert_sort = function(arr){
    const {length} = arr;
    for(let i = 1; i < length; i++) {
      for(let j = i; j > 0; j --) {//要维护的有序序列
        if(arr[j] < arr[j-1]){
          [arr[j-1], arr[j]] = [arr[j], arr[j-1]]
        }
      }
    }
    return arr;
  }

3、选择排序

数组里选择最小(大)的值依次和有序序列的末尾位置的数值交换,比如第一次就是找到最小(大)的值和第一个位置的数交换位置,事件复杂度O(n^2),不稳定。

 const choose_sort = function(arr){
    const {length} = arr;
    for(let i = 0; i < length; i++){
      let min_index = i;
      for(let j = i; j < length; j ++){
        min_index = arr[j + 1] < arr[min_index] ? j+1 : min_index;       
      }
      [arr[i], arr[min_index]] = [arr[min_index], arr[i]]
    }
    return arr;
  }

4、快速排序

快排采用分治法,也是交换排序的一种,是冒泡排序的优化版,选择一个基值,通过比较交换把比它小的放它左边,比它大的放它右边,得到的两个序列再找一个基值,继续做比较交换,依次递归。时间复杂度O(nlog2n) ~ O(n^2),不稳定。

const quick_sort = function(arr){
    let {length} = arr;
    const sort = (subArr, left = 0, right = length - 1)=>{
      if(left >= right) return;
      let key = subArr[left]; 
      let first = left;     
      let last = right;
      while(left < right){
        while(subArr[left] <= key && left < right) {
          left ++;
        }
        while(subArr[right] >= key && left < right) {
          right --;
        }
        [subArr[left], subArr[right]] = [subArr[right], subArr[left]];
      }
      sort(subArr, first, right-1);
      sort(subArr, right, last)
    }
    sort(arr);
    return arr;

  }

5、堆排序

堆排序是选择排序的一种,堆其实就是把序列看作一个完全二叉树,从未排序的末端节点依次递归到根节点,做子节点和父节点数值的比较替换,保证父节点数值总是大(小)于等于子节点,得到大(小)顶堆,然后把根节点数值和未排序末端节点数值交换(和根节点交换过数值的节点组成有序序列),然后再继续下一轮的大(小)顶堆的调整。时间复杂度O(nlog2n),不稳定。

const heap_sort = function(arr){
    const {length} = arr;
    const changeMax = (sub_arr, root, limit) => {
      let l_child = 2 * root + 1,
      r_child = 2  * root + 2;
      
      let max_child = r_child <= limit && sub_arr[l_child] < sub_arr[r_child] ? r_child : l_child;
      if(max_child <= limit && sub_arr[root] < sub_arr[max_child]) {
        [sub_arr[root], sub_arr[max_child]] = [sub_arr[max_child], sub_arr[root]]
      }    
    }

    for(let i = length - 1; i >= 0; i--){
      for(let j = Math.round(i/2) -1; j >= 0; j --){
        changeMax(arr, j, i)
      }
      [arr[i], arr[0]] = [arr[0],arr[i]]
    }
    return arr;
    
  }

6、归并排序

归并排序也成为了合并排序,把序列分成n(序列长度)个小序列,然后进行两两合并得到[n/2]个有序小序列,然后再进行两两合并,依次循环直到所有有序序列的合而为一,最终得到一个长度为n的有序序列。时间复杂度O(nlog2n),稳定。

const 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());     
        }
      }
      if(left.length > 0){
        result.push(...left)
      }
      if(right.length > 0){
        result.push(...right)
      }
      return result;
    }
  const merge_sort = function(arr){
    const {length : l} = arr;
    if(l < 2) return arr;
    const middle = Math.floor(l / 2),
      left_arr = arr.slice(0, middle),
      right_arr = arr.slice(middle, l);
    return merge(merge_sort(left_arr),merge_sort(right_arr));  
  }

总结:

排序算法的复杂度和稳定性
类别方法时间复杂度空间复杂度稳定性
最差平均辅助存储
插入排序O(n^2)O(n^2)O(1)稳定
归并排序O(nlog2n)O(nlog2n)O(n)稳定
选择选择排序O(n^2)O(n^2)O(1)不稳定
堆排序O(nlog2n)O(nlog2n)O(1)不稳定
交换冒泡排序O(n^2)O(n^2)O(1)稳定
快速排序O(n^2)O(nlog2n)O(1)不稳定

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值