常见排序 ts实现

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 希尔排序
  • 归并排
  • 快排
const testData = [64, 34, 25, 12, 22, 11, 90]

/** 交换两个数在数组中的位置 */
const swap = (arr: number[], i: number, j: number) => {
  if (arr.length === 0) return []
  const temp = arr[i]
  arr[i] = arr[j]
  arr[j] = temp
}

/**
 * 冒泡排序
 * 
 * ① 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
 * 
 * ② 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
 * 
 * ③ 针对所有的元素重复以上的步骤,除了最后一个。
 * 
 * ④ 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
 */
function bubbleSort(arr: number[]) {
  if (arr.length === 0) return []
  const _arr = [...arr]
  const n = _arr.length - 1

  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n - i - 1; j++) {
      if (_arr[j] > _arr[j + 1]) swap(_arr, j, j + 1)
    }
  }
  return _arr
}

/** 
 * 选择排序
 * 
 * ① 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
 * 
 * ② 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
 * 
 * ③ 重复第二步,直到所有元素均排序完毕。
 */
function selectSort(arr: number[]) {
  if (arr.length === 0) return []
  const _arr = [...arr]
  const n = _arr.length - 1

  for (let i = 0; i < n; i++) {
    let minIndex = i
    for (let j = i; j < n; j++) {
      if (_arr[j] < _arr[minIndex]) minIndex = j
    }
    swap(_arr, i, minIndex)
  }
  return _arr
}

/**
 * 插入排序
 * 
 * ① 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
 * 
 * ② 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
 */
function insertSort(arr: number[]) {
  if (arr.length === 0) return []
  const _arr = [...arr]
  const n = _arr.length - 1

  for (let i = 0; i < n; i++) {
    let preIndex = i - 1
    const current = _arr[i]
    while (preIndex >= 0 && _arr[preIndex] > current) {
      _arr[preIndex + 1] = _arr[preIndex]
      preIndex--
    }
    _arr[preIndex + 1] = current
  }
  return _arr
}

/** 
 * 希尔排序
 * 
 * ① 取间隔将数组相同间隔的数字分为一组(一般初始间隔为数组长度一半),在组内使用插入排序(在使用插入排序时依然从队列头部依次取数字进行比较,只是比较对象不是前1个而是前gap个)
 * 
 * ② 每次将间隔取半,执行第①步,直到间隔为1
 */
function shellSort(arr: number[]) {
  if (arr.length === 0) return []
  const _arr = [...arr]
  const len = _arr.length

  let gap = Math.floor(len / 2)
  while (gap > 0) {

    for (let i = 1; i < len; i++) {
      let current = _arr[i]
      let preIndex = i - gap
      while (preIndex >= 0 && _arr[preIndex] > current) {
        _arr[preIndex + gap] = _arr[preIndex]
        preIndex -= gap
      }
      _arr[preIndex + gap] = current
    }
    gap = Math.floor(gap / 2)
  }
  return _arr
}


/**
 * 归并排
 * 
 * ① 传入两个有序数组(数组长度为1一定有序),一直比较两个数组的第一个值大小,将小的弹出放在结果数组末尾,直到一个数组为空。
 * 
 * ② 此时不为空的数组一定全部大于结果数组,全部放在结果数组末尾即可。
 */
const  merge = (left:number[],right:number[]) => {
  const res:number[] = []
  while(left.length && right.length){
    if(left[0] < right[0]) res.push(left.shift() as number)
    else res.push(right.shift() as number)
  }
  if(left.length) return res.concat(left)
  if(right.length) return res.concat(right)
} 

function mergeSort(arr:number[]):number[]{
  if(arr.length < 2) return arr
  const _arr = [...arr]
  const len = _arr.length

  const middle = Math.floor(len / 2)
  const left = _arr.slice(0,middle)
  const right = _arr.slice(middle)

  return merge(mergeSort(left),mergeSort(right)) as number[]
}

/**
 * 快排
 * 
 * ① 取数组第一个为基准点(如果没有元组返回空数组),循环后面的数,如果比基准点小放在左数组中,反之放在右数组中。
 * 
 * ② 对左数组和右数组进行快排(递归),此时返回的数组已经有序,返回[左数组,基准点,右数组]的组合数组即可
 */
function quickSort(arr: number[]): number[] {
  if (arr.length === 0) return []

  const left: number[] = [], right: number[] = []
  const pivot = arr[0]
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] < pivot) left.push(arr[i])
    else right.push(arr[i])
  }
  return [...quickSort(left), pivot, ...quickSort(right)]
}

console.log(`冒泡:${bubbleSort(testData)}`);
console.log(`选择:${selectSort(testData)}`);
console.log(`插入:${insertSort(testData)}`);
console.log(`希尔:${shellSort(testData)}`);
console.log(`归并排:${mergeSort(testData)}`);
console.log(`快排:${quickSort(testData)}`);
console.log(`原始数组:${testData}`);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值