几种常见排序算法的JavaScript实现

就JavaScript而言,Array对象有方法sort()可以对数组成员进行排序,默认是字典顺序。自定义排序规则需要给sort()方法提供一个函数。此函数本身有2个参数,表示进行比较的两个元素。如果返回值大于0,表示第1个元素在后面,其他情况下第1个元素在前面。

下面时其他排序算法的代码,扩充Array的排序功能。

稳定的排序

冒泡排序

时间复杂度是O(n2)

代码如下:

Array.prototype.bubbleSort = function() {
  var len = this.length
  var temp = 0
  while (len) {
    for (var i = 1; i < len; i++) {
      if (this[i-1] > this[i]) { //升序排列
        temp = this[i-1]
        this[i-1] = this[i]
        this[i] = temp
      }
    }
    len--
  }
}

插入排序

时间复杂度是O(n2)

代码如下:

Array.prototype.insertionSort = function() {
  var i, j, temp
  var len = this.length
  for (i = 1; i < len; i++) {
    temp = this[i]  //无序区的第一个元素
    for (j = i - 1; j >= 0 && this[j] > temp; j--)
      this[j+1] = this[j]
    this[j+1] = temp
  }
}

可以视为将数组分成两个区域:(有序区,无序区)

过程:把无序区的第一个元素插入到有序区的合适的位置。

操作:比较得少,换得多。

归并排序

时间复杂度是O(n log n);需要O(n)额外空间

代码如下:

Array.prototype.mergeSort = function() {
  //合并
  var merge = function(left, right) {
    var final = []
    while (left.length && right.length)
      final.push(left[0] <= right[0] ? left.shift() : right.shift())
    return final.concat(left.concat(right))
  }
  //递归分块
  var len = this.length
  if (len < 2) return this
  var mid = len >> 1
  return merge(this.slice(0,mid).mergeSort(),this.slice(mid).mergeSort())
}

不稳定的排序

选择排序

时间复杂度是O(n2)

代码如下:

Array.prototype.selectionSort = function() {
  var i, j, min, temp
  var len = this.length
  for (i = 0; i < len - 1; i++) {
    min = i
    for (j = i + 1; j < len; j++)
      if (this[min] > this[j]) min = j
    temp = this[min]
    this[min] = this[i]
    this[i] = temp
  }
}

将数组分为两个部分:(有序区,无序区)

过程:在无序区里找一个最小的元素跟在有序区的后面

操作:比较得多,换得少。

希尔排序

时间复杂度是O(n log2 n) (log n)的平方 略差于比较算法的 O(n log n)。

也称递减增量排序算法,是插入排序的一种更高效的改进版本,通过将待比较的元素分成几个区域来提升插入排序的性能。(插入排序对于接近排好的数据进行操作时效率很高,可达到线性)

→ 关键在于步长的选择。

代码如下:

Array.prototype.shellSort = function() {
  var gap, i, j, temp
  var len = this.length
  for (gap = len >> 1; gap > 0; gap >>= 1) //步长折半
    for (i = gap; i < len; i++) {
      temp = this[i]
      for (j = i - gap; j >= 0 && this[j] > temp; j -= gap)
        this[j + gap] = this[j]
      this[j + gap] = temp
    }
}

堆排序

时间复杂度为O(n log n)

代码如下:

Array.prototype.heapSort = function() {
  var arr = this.slice(0)
  function swap(i, j) { //封装交换操作
    var temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
  }
  function max_heapify(start, end) { //最大堆调整。使得根节点为堆的最大值
    var dad = start
    var son = dad * 2 + 1
    if (son >= end) return //递归终止条件
    if (son + 1 < end && arr[son] < arr[son + 1]) son++ //选择左右子节点中的大者
    if (arr[dad] <= arr[son]) {
      swap(dad, son)
      max_heapify(son, end)
    }
  }
  var len = arr.length
  //初始化,i从最后一个父节点开始往前调整。最终数组第一个元素为最大值
  for (var i = (len >> 1) - 1; i >= 0; i--) max_heapify(i, len)
  //把堆顶元素交换到末位(进入有序区),然后剩余元素再次进行调整,直至排序结束
  for (var i = len - 1; i > 0; i--) {
    swap(0, i)
    max_heapify(0, i)
  }
  return arr
}

可把数组看作2部分:(最大堆,有序区)

过程:从堆顶把根卸出来放在有序区之前,然后在调整最大堆。

快速排序

时间复杂度为平均O(n log n),最坏O(n2)。适合于大的、随机数列表。

代码如下:

Array.prototype.quickSort = function() {
  var len = this.length
  if (len <= 1) return this.slice(0)
  var left = []
  var right = []
  var mid = [this[0]]
  for (var i = 1; i < len; i++)
    if (this[i] < mid[0])
      left.push(this[i])
    else
      right.push(this[i])
  return left.quickSort().concat(mid.concat(right.quickSort()))
}

参考:

排序算法 - 维基百科

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值