js的十种排序算法

作者: 转移到CSDN名字丹丹的小跟班 | 来源:发表于2021-02-19 17:01 被阅读0次
十大算法解析
  • n: 数据规模
  • k:“桶”的个数
  • In-place: 占用常数内存,不占用额外内存
  • Out-place: 占用额外内存
  • 稳定性:排序后2个相等键值的顺序和排序之前它们的顺序相同

O(1), O(n), O(logn), O(nlogn) 的区别

1.冒泡排序

原理:
对一个数组里的前一个数和后一个数进行比较,把两者之间最大的数放在后面,循环一轮之后最大的就在末尾了。然后同理在排序剩下的n-1 ,n-2 …个数

冒泡排序动画演示

为什么会有两个for循环:之所以在最外层嵌套一个for循环是因为如果仅仅只有一个for循环,那么两两比较之后,只会让最大的值在数组末尾(也就是只执行了一轮),前面的数字依旧不是有序的。第一个for循环用于控制他的轮数,第二个控制比较的次数。
第二个for循环里面为什么要-i:因为i表示的是已经排序好了的最大数的长度(从右数第i个数都是已经排序好了的),不勇再参与排序,为了更简洁快速,所以进行-i操作。
第一个循环为什么要-1:不需要同自己比较,所需轮数只要数组长度-1就可以了。
第二个循环为什么要 - 1 - i:因为比较的次数首先要排除同自身比较,所以-1,其次循环了i轮,那么就有i个元素已经排序好处于数组末尾,也应省略。

function bubbleSort(arr) {
  for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        //数组元素位置替换
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
      }
    }
  }
  return arr;
}
2.选择排序

原理:

  • 外层遍历数组,拿到下标保存
  • 内层再次遍历数组,将每个元素与外层保存的下标对应元素进行比较,将较小的值的下标进行保存
  • 内层遍历结束找到了最小值的下标,与外层保存的下标对应的值交换位置
选择排序动画演示

为什么有 minIndex = i:当判断arr[j] < arr[minIndex]如果不成立时,第二个的循环完成之后执行元素替换工作时,minIndex就会因不存在而报错。
为什么要len - 1:因为在第二个循环里最后一项是会跟所有项进行比较的,所以第一个循环的数组的最后一个元素已经比较过,不用重复比较。
第二个循环为什么要i + 1:因为经过元素替换后,i及i之前的下标的数组是已经排序好的最小元素,不用在参与比较。

function selectionSort(arr) {
  var len = arr.length;
//最小值的下标
  var minIndex;
  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; //将最小数的索引保存
      }
    }
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
  }
  return arr;
}
3.插入排序

原理:
遍历数组,从后向前进行比较,符合条件交换位置。

插入排序动画演示

第一个循环为什么不从0开始:因为是从后向前进行比较,下标为0的元素前面没有值,所以从0开始无意义。
第二个循环为什么进行--操作:因为是从后向前进行比较

function insertSort(arr) {
  for (let i = 1; i < arr.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;
}
4.快速排序

原理

  • 先从数列中取出一个数作为“基准”。
  • 分区过程:将比这个“基准”大的数全放到“基准”的右边,小于或等于“基准”的数全放到“基准”的左边。
  • 再对左右区间重复第二步,直到各区间只有一个数。

quickSort(left).concat([middleItem], quickSort(right)):这里是利用递归调用函数进行不断的分段排序,最后使用concat方法合并。注意这里的合并顺序必须是先左分段数组,在基准值,最后在右边的数组。
arr.splice(midINdex, 1)[0]:使用splice取到中间基值,此方法修改掉了原数组。因为每次最后的拼接都会将中间基值拼接起来,如果不删除基值会造成拼接重复。

function quickSort(arr) {
    if (arr.length <= 1) {
    return arr;
    }
  let len = arr.length;
  let midINdex = Math.floor(len / 2);
  let midItem = arr.splice(midINdex, 1)[0];
  let left = [];
  let right = [];
  for (let i = 0; i < len - 1; i++) {
  if (arr[i] < midItem) {
    left.push(arr[i]);
      } else {
    right.push(arr[i]);
    }
  }
  return quickSort(left).concat([midItem], quickSort(right));
  }
5.归并排序

原理
归并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

归并排序动图演示

result.concat(leftArr).concat(rightArr):之所以最后要进行拼接操作,是因为有可能两边数组比较后,一边还有剩余(如一边的值特小,一边特大),所以要进行拼接。

function mergeSort(array) {
  if (array.length == 1) return array;
  var middle = Math.floor(array.length / 2); 
  var left = array.slice(0, middle); 
  var right = array.slice(middle);
  return merge(mergeSort(left), mergeSort(right)); 

function merge(leftArr, rightArr) {
  var result = [];
  while (leftArr.length > 0 && rightArr.length > 0) {
    if (leftArr[0] < rightArr[0]) result.push(leftArr.shift());
    else result.push(rightArr.shift());
  }
  return result.concat(leftArr).concat(rightArr); 
}
6.计数排序

原理
理由数组下标天然排序的原理,以数组元素值为键,出现次数为值存进一个临时数组,最后再遍历这个临时数组还原回原数组。

function countSort(arr) {
  //克隆原数组
  let cloneArr = Array.from(arr)
  // 定义一个空数组
  let arr2 = []; 
  // 找到这个数组的 最大 最小值
  let max = Math.max(...cloneArr); 
  let min = Math.min(...cloneArr);
  // 定义一个索引 这个索引是 后面用来改变原数组的

  let index = 0; 
  // 装桶操作
  for (let i = 0, len = cloneArr.length; i < len; i++) {
    // 把传入数组的值作为下标  装入一个长度为数组最大值长度的临时数组
    let temp = cloneArr[i];
    arr2[temp] = 1;
  }
  // 还原原数组
  for (let i = min; i <= max; i++) {
    // 如果arr2[i] > 0表示他的下标是从原数组获取的,需要进行还原操作
     if(arr2[i] > 0) {
       // 就把原数组的第index位赋值为 i(i本身就是从数组里获取的下标)
      cloneArr[index] = i;
       //赋值完成后进行+1操作,等待给原数组下一位赋值
      index ++
      // 每赋值完一次后 临时数组当前位的值就--,原本值为1,--就为0了,如果=0 就说明这位上没有值了,则不会进行赋值操作
      arr2[i]--; 
    }
  }
  return cloneArr;
}
7.桶排序
//插入排序方法(在各个桶里调用)
function insertSort(arr) {
  for (let i = 1; i < arr.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;
}
//桶排序
function bucketSort(arr, bucketCount) {
  let result = [];
  // 找出最大值和最小值,为给每个桶分配大小做准备
  let minValue = Math.min(...arr);
  let maxValue = Math.max(...arr);

  // 求得每个桶的大小
  bucketSize = Math.ceil(maxValue / bucketCount);
  //创建桶
  bucket = new Array(bucketCount);
  for (let i = 0; i < bucketCount; i++) {
    bucket[i] = [];
  }
  // 往桶里放数据
  for (let i = 0; i < arr.length; i++) {
    bucket[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
  }
  // 对每个桶进行单独排序,放进结果数组中
  for (let i = 0; i < bucketCount; i++) {
    let data = insertSort(bucket[i])
    let len = data.length
    if(len > 0) {
      data.forEach(item => {
        result.push(item)
      });
    }
  }
  return result;
}
8.希尔排序(未理解)
function shellSort(arr) {
  let len = arr.length;
  // gap 即为增量
  for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
    console.log("gap", gap)
    for (let i = gap; i < len; i++) {
      console.log('i', i)
      let j = i;
      let current = arr[i];
      while(j - gap >= 0 && current < arr[j - gap]) {
        arr[j] = arr[j - gap];
        j = j - gap;
      }
      arr[j] = current;
    }
  }
}

相关文章

  • 排序算法

    十种常见排序算法:

  • 算法收集

    十种常见排序算法

  • 常见十大排序算法概述

    排序算法概述 网上常见的排序算法有十种:冒泡排序、快速排序、插入排序、希尔排序、选择排序、堆排序、归并排序、计数排...

  • 常用排序算法

    转载 十大经典排序算法(动图演示) 0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:...

  • 排序算法

    转载自-十大经典排序算法(动图演示) 0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序...

  • js的十种排序算法

    n: 数据规模k:“桶”的个数In-place: 占用常数内存,不占用额外内存Out-place: 占用额外内存稳...

  • 2022-02-21 排序算法专栏

    排序算法类别 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复...

  • 排序算法汇总

    0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于...

  • 数据结构经典排序算法(动图演示)

    0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于...

  • 十大经典排序算法(动图演示)

    0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于...

网友评论

    本文标题:js的十种排序算法

    本文链接:https://www.haomeiwen.com/subject/jbaoxltx.html