在javascript中,十大排序算法

912. 排序数组

排序总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32VQSgpU-1665396147681)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6c94713cc9cd450c9608dc4da4672b75~tplv-k3u1fbpfcp-watermark.image?)]

1、 冒泡排序

Bubble Sort 是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

var arr = [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
var crr = arr.sort(() => Math.random() - 0.5);
for (var i = 0; i < crr.length; i++) {
    for (var j = i; j < crr.length; j++) {
        if (crr[i] > crr[j]) {
            [crr[i], crr[j]] = [crr[j], crr[i]];
        }
    }
}

2、 快速排序

快速排序(Quicksort)步骤

  1. 首先设定一个分界值,通过该分界值将数组分成左右两部分。
  2. 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
  3. 左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理
  4. 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
  • 时间复杂度:O(nlogn),最优为O(nlogn),最坏为O(n²),平均为O(nlogn)。
  • 空间复杂度:O(logn)
var sortArray = function (nums) {
  let len = nums.length
  if (len === 1) {
      return nums
  }
  quickSort(nums, 0, len - 1)
  function quickSort(nums, left, right) {
      if (left < right) {
          let pivot = partition(nums, left, right)
          quickSort(nums, left, pivot - 1)
          quickSort(nums, pivot + 1, right)
      }
  }
  function partition(nums, left, right) {
      let i = left, j = right + 1
      let pivot = nums[left]
      while (true) {
          while (nums[++i] < pivot) {
              if (i === right) {
                  break
              }
          }
          while (pivot < nums[--j]) {
              if (j === left) {
                  break
              }
          }
          if (i >= j) {
              break
          }
          [nums[i], nums[j]] = [nums[j], nums[i]]
      }
      if(left != j){
        [nums[left], nums[j]] = [nums[j], nums[left]]
      }
      return j
  }
  return nums
};
console.log(sortArray([5,3,1,4,2,7,6]))

在代码中,分别在这几个位置打上断点,可以理解代码走的流程,如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EVcp9kFL-1665396147682)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0f4b17f4ee5d4d6fbe507ae84892b078~tplv-k3u1fbpfcp-watermark.image?)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUbSWdbj-1665396147682)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa8d93008bc743c1bfd8c64f43314598~tplv-k3u1fbpfcp-watermark.image?)]

3、选择排序

选择排序(Selection sort)工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

时间复杂度:O(n²),最优为O(n²),最坏为O(n²),平均为O(n²)。
空间复杂度:O(1)

var sortArray = function (nums) {
    let len = nums.length;
    if (len === 1) {
        return nums;
    }
    for (let i = 0; i < len; i++) {
        let minIndex = i
        for (let j = i + 1; j <len; j++) {
            if (nums[j] < nums[minIndex]) {
                minIndex = j
            }
        }
        if (minIndex !== i) {
            [nums[minIndex], nums[i]] = [nums[i], nums[minIndex]]
        }
    }
    return nums
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yx7oRIB5-1665396147683)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1e3515e87eea40028e2e9ffac3cad0b1~tplv-k3u1fbpfcp-watermark.image?)]

4、插入排序

插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序的基本思想是在一个已经排好序的有序表中,插入一个新的值,重新排序冒泡一次,直到被插入的值找到的合适的位置结束,进行下一次循环

时间复杂度:O(n²),最优为O(n),最坏为O(n²),平均为O(n²)。
空间复杂度:O(1)

var sortArray = function (nums) {
    let len = nums.length;
    if (len === 1) {
        return nums;
    }
    for (let i = 1; i < nums.length; i++) {
        for (let j = i; j > 0 && (nums[j] < nums[j - 1]); j--) {
            [nums[j], nums[j - 1]] = [nums[j - 1], nums[j]]
        }
    }
    return nums
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXDr29Zs-1665396147683)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/01f7d5bf446e4b5288b560b5b3639291~tplv-k3u1fbpfcp-watermark.image?)]

5、 希尔排序

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

代码实现在这里

var sortArray = function(nums) {
    var h = 1
    var len  = nums.length
    while(h < len/2){
        h  = 2*h + 1
    }
    while(h>=1){
        for(var i = h;i<len;i++){
            for(var j = i;j>= h && nums[j] < nums[j - h] ; j = j - h){

                [nums[j],nums[j-h]] = [nums[j-h],nums[j]]
            }
        }

        h = h >> 1
    }
    return nums
};

调试代码 加下面

var brr = [];
for (var i = 0; i < 10; i++) {
  brr.push(i);
}
var arr = brr.sort(function () {
  return Math.random() - 0.5;
});
console.log(arr);
console.log(sortArray([0, 1, 9, 7, 6, 8, 2, 3, 4, 5]));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zr2EGcpU-1665396147683)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92dbfa7115454122a2e1257b5d4f2a44~tplv-k3u1fbpfcp-watermark.image?)]

6、归并排序

归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

代码实现

var sortArray = function (nums) {
    function merge(left, right) {
        const res = []
        while (left.length && right.length) {
            if (left[0] < right[0]) {
                res.push(left.shift())
            } else {
                res.push(right.shift())
            }
        }
        return res.concat(left).concat(right)
    }
    function mergeSort(nums) {
        const len = nums.length
        if (len === 1) {
            return nums;
        }
        const mid = len >> 1
        const left = nums.slice(0, mid)
        const right = nums.slice(mid)
        return merge(mergeSort(left), mergeSort(right))
    }
    return mergeSort(nums)
};

调试代码

var brr = [];
for (var i = 0; i < 10; i++) {
  brr.push(i);
}
var arr = brr.sort(function () {
  return Math.random() - 0.5;
});
console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([0, 1, 9, 7, 6, 8, 2, 5, 4, 3]));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kS28wx3o-1665396147684)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77dcedc776be4523956b30ef9eaf9ea5~tplv-k3u1fbpfcp-watermark.image?)]

7、 桶排序

var sortArray = function(nums) {
    var len = nums.length;
    if(len <=1){
        return nums
    }
    var max = nums[0]
    var min = nums[0]

    for(var i = 1;i<len;i++){
        if(nums[i]>max){
            max = nums[i]
        }
        if(nums[i]<min){
            min = nums[i]
        }
    }
    var arr = []
    for(var i =0;i<len;i++){
        var j = Math.floor((nums[i] - min) / 3) >> 1
        if(!arr[j]){
            arr[j] = []
        }
        arr[j].push(nums[i])
    }
    var arrNums = Math.floor((max - min ) / 3) + 1
    nums = []
    for(var j =0;j<arrNums;j++){
        if(arr[j]){
            insertSort(arr[j])
            nums = nums.concat(arr[j])
        }
    }
    return nums
    function insertSort(brr){
        var len = brr.length;
        for(var i=1;i<len;i++){
            for(var j = i;j>0 && brr[j] < brr[j - 1];j--){
                [brr[j],brr[j-1]] = [brr[j-1],brr[j]]
            }
        }
        return brr
    }
};

8、 基数排序

  • Radix Sort,非比较型整数排序,将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
  • 非比较排序因为不涉及比较,其基本操作的代价较小,所以在一定情况下,基数排序一般要快过基于比较的排序,比如快速排序。

代码实现

var sortArray = function (nums) {
  let len = nums.length;
  if (len < 2) {
    return nums;
  }
  // nums的最大值
  let max = Math.max.apply(null, nums);
  // max的位数,如131就是3位
  let maxDigit = 1;
  while ((max = Math.floor(max / 10))) {
    maxDigit++;
  }
  var count = [];
  let mod = 10;
  let dev = 1;
  for (let i = 0; i < maxDigit; i++) {
    count = [];
    for (let j = 0; j < len; j++) {
      var item = nums[j]
      var bucket = Math.floor((nums[j] % mod) / dev);
      console.log(item);
      console.log(bucket);
      if (count[bucket]) {
        count[bucket].push(nums[j]);
      } else {
        count[bucket] = [nums[j]];
      }
    }
    console.log(count);
    let pos = 0;
    for (let j = 0; j < count.length; j++) {
      let value = null;
      if (count[j]) {
        while ((value = count[j].shift()) != null) {
          nums[pos++] = value;
        }
      }
    }
    dev *= 10;
    mod *= 10;
  }

  return nums;
};
var brr = [];
for (var i = 0; i < 700; i = i * 2 + 1) {
  brr.push(i);
}
var arr = brr.sort(function () {
  return Math.random() - 0.5;
});
// console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([21, 7, 19, 10, 1, 23, 16, 12, 8, 5]));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Gap6hwn-1665396147684)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ff64cf7558ee420c9016554074b91dbb~tplv-k3u1fbpfcp-watermark.image?)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZBbdzb4z-1665396147684)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d5c03919df004bae95c1e46b98c53620~tplv-k3u1fbpfcp-watermark.image?)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BmMRDP6M-1665396147684)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/efaaf10301f349dfbbf18a66c2f19a42~tplv-k3u1fbpfcp-watermark.image?)]

9、 堆排序

var sortArray = function (nums, size=3) {
    let len = nums.length
    if(len<2) {
        return nums
    }

    const half = len >> 1
    let i = half - 1
    while(i>=0) {
        max_heapify(nums,i ,len)
        i--
    }

    for(let i = len-1; i>0; i--) {
        swap(nums, 0, i)
        max_heapify(nums, 0, i)
    }
    
    return nums
};

function max_heapify(arr, start, end) {
    let parentIndex = start, sonIndex = parentIndex*2 + 1

    if(sonIndex>=end) {
        return
    }

    // 左子节点<右子节点
    if(sonIndex+1<end && arr[sonIndex]<arr[sonIndex+1]) {
        sonIndex++
    } 
    if(arr[parentIndex]<arr[sonIndex]) {
        swap(arr, parentIndex, sonIndex)
        max_heapify(arr, sonIndex, end)
    }
}

function swap(a, i,j) {
    [ a[i], a[j] ] = [ a[j], a[i] ]
}

10、 计数排序

  • 计数排序不是一个比较的排序算法,元素从未排序状态变为已排序状态的过程,是由额外空间的辅助和元素本身的值决定的。它的优势在于对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k) > O(nlogn)的时候其效率反而不如基于比较的排序,因为基于比较的排序的时间复杂度在理论上的下限是O(nlogn)。
  • 由于用来计数的数组count的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。

代码实现

var sortArray = function (nums) {
  let len = nums.length
  if(len<2) {
      return nums
  }
  const count = []
  for(let i=0; i<len; i++) {
      const j = nums[i]
      if(count[j]) {
           count[j] ++
      } else {
          count[j] = 1
      }
  }
  const res = []
  for(let j=0; j<count.length; j++) {
      if(count[j]) {
          while(count[j]>0) {
              res.push(j)
              count[j] -- 
          }
      }
  }
  return res
};

调试代码

var brr = [];
for (var i = 0; i < 700; i = i*2 + 1) {
  brr.push(i);
}
var arr = brr.sort(function () {
  return Math.random() - 0.5;
});
// console.log(arr);
// console.log(sortArray(arr));
console.log(sortArray([21, 7, 19, 10, 1, 23, 16, 12, 8, 5,5]));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-irL3gQ2l-1665396147685)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/04ca096be60d4f23949cb6118f451edd~tplv-k3u1fbpfcp-watermark.image?)]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值