炫酷的js十大排序算法(上)

十大排序算法可以分成两类:

  • 比较类别排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
     
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。


     

算法的时间复杂度:

冒泡排序

通过相邻元素的比较和交换,使得每一趟循环都能找到未有序数组的最大值或最小值。

内循环: 使用相邻双指针 j , j + 1 从左至右遍历,依次比较相邻元素大小,若左元素大于右元素则将它们交换;遍历完成时,最大元素会被交换至数组最右边 。

外循环: 不断重复「内循环」,每轮将当前最大元素交换至 剩余未排序数组最右边 ,直至所有元素都被交换至正确位置时结束。

代码 

function bubbleSort(arr) {
  var len1 = arr.length;
  // 一共比较多少趟
  for (var i = 0; i < len1 - 1; i++) {
    // 每趟进行比较,j=要进行排序的元素个数,每一趟排下来最后1个元素都不进行下一趟的排序
    for (var j = 0; j < len1 - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}
 
var arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
 
console.log(bubbleSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

选择排序 

思路:依次找到剩余元素的最小值或者最大值,放置在末尾或者开头。

 代码 

function selectSort(arr) {
  let len1 = arr.length;
  for (var i = 0; i < len1 - 1; i++) {
    var minIndex = i;  // 记录最小元素的索引
    for (var j = i + 1; j < len1; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j;   // 如果有遇到比首元素小的,就记录该索引,这样就能找到当前趟最小元素的索引
      }
    }
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];  // 交换首元素和最小元素的位置
  }
  return arr;
}
 
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
 
console.log(selectSort(arr));  // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
 

 希尔排序

通过某个增量 gap,将整个序列分给若干组,从后往前进行组内成员的比较和交换,随后逐步缩小增量至 1。希尔排序类似于插入排序,只是一开始向前移动的步数从 1 变成了 gap

1、选择一个增量 k=arr.length/2 进行排序,增量k为几就将该arr分成几组,每组有 arr.length/k=2 个元素。然后组内元素从前往后进行比较,按照升序排列好,再将小组并成一个大arr。
2、再次分组,分成k/2组,每个组有 arr.length/k/2 个元素,再次将组内元素按升序进行排序,排序好在并成大arr。
3、重复上述操作,直至arr排好序。
4、插入排序时,并不是一个分组内的数字一次性用插入排序完成,而是每个分组交叉进行。

代码

function shellSort(arr) {
  var len1 = arr.length;
  // 第一次分组是k=arr.length/2,之后的每次分组都是k/2
  for (var k = Math.floor(len / 2); k > 0; k = Math.floor(k / 2)) {
    // 遍历每个分组的元素,i在分组里表示的是每个组内最后一个元素
    // 在原数组arr里表示的是分组后的第一个元素,然后后面的元素依次与前面的元素进行比较
    for (var i = k; i < len1; i++) { // i控制当前进行排序的是哪一个小组
      var j = i;  // j控制的是当前小组的最后一个元素
      // 各小组内进行比较时,按升序排列
      while (j - k >= 0 && arr[j] < arr[j - k]) {
        [arr[j], arr[j - k]] = [arr[j - k], arr[j]];
        j = j - k;  // 让j变成当前小组的上一个元素
      }
    }
  }
  return arr;
}
 
var arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
 
console.log(shellSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

归并排序

 把长度为n的arr分成两个长度为n/2的子序列,一直划分到最小个数之后,两两比较,合并成长度为2的小序列,然后再小序列间比较,一直重复合并成最终的arr

代码 

function mergeSort(arr) {
  var len1 = arr.length;
  if (len1 < 2) {
    return arr;
  }
  var mid = Math.floor(len1 / 2);
  var left = arr.slice(0, mid);
  var right = arr.slice(mid);
  return merge(mergeSort(left), mergeSort(right));
}
 
function merge(left, right) {
  var 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;
}
 
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
 
console.log(mergeSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

快速排序

快速排序算法是一种基于分治思想的排序算法,其核心思路在于通过选取一个基准值,将待排序数组划分为左右两个子序列,其中左侧序列所有元素均小于基准值,右侧序列所有元素均大于基准值。之后对左右子序列递归进行快排操作,最终将整个序列排好序。

 

 

代码

 

 var arr = [9, 16, 8, 10, 19];
        var quickSort2 = function(arr) {
            if (arr.length <= 1) {
                return arr;
            }
            var pivotIndex = Math.floor(arr.length / 2);
            var pivot = arr.splice(pivotIndex, 1);
            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 quickSort2(left).concat([pivot], quickSort2(right));
        };
        quickSort2(arr)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值