归并排序和计数排序

96 阅读1分钟

归并排序

将每个元素拆分成大小为1的分区

递归地合并相邻的分区

遍历 i = 左侧首项位置 到 右侧末项位置

如果左侧首项的值 <= 右侧首项的值

拷贝左侧首项的值

否则: 拷贝右侧首项的值; 增加逆序数

将元素拷贝进原来的数组中

代码实现

let mergeSort = arr =>{
  let k = arr.length
  if(k===1){return arr}   //数组长度为一,即默认每个数自己是排好队的
  //把数组分为左边和右边两个数组
  let left = arr.slice(0, Math.floor(k/2))  //左
  let right = arr.slice(Math.floor(k/2))    //右
  return merge(
  //把右边的数组和右边的数组再进行mergeSort操作(分左右,直到每个数
  mergeSort(left), mergeSort(right)组内只有一个元素)
  )
}
//下面这个部分,语言很难表述清楚,是数组合并的过程
let merge = (a, b) => {
  if(a.length === 0) return b
  if(b.length === 0) return a
  return a[0] > b[0] ?
     [b[0]].concat(merge(a, b.slice(1))) :
     [a[0]].concat(merge(a.slice(1), b))
}

merge过程示意图

图片

计数排序

创建关键值(计数)数组

遍历数列中的每个元素

相应的计数器增加 1

每轮计数,都从最小的值开始

当计数为非零数时

重新将元素存储于列表

将计数减1

代码实现

let countSort = arr =>{
  let hashTable = {}, max = 0, result = []   //假设这个数组中最大的数是0,用来存放排列好的数组是result
  // 遍历数组
  for(let i=0; i<arr.length; i++){ 
    if(!(arr[i] in hashTable)){ 
      hashTable[arr[i]] = 1
    }else{
      hashTable[arr[i]] += 1
    }
    if(arr[i] > max) {max = arr[i]}
  }
  // 遍历哈希表
  for(let j=0; j<=max; j++){ 
    if(j in hashTable){
    //如果相同的数字出现多次,出现几次push这个数几次
      for(let i = 0; i<hashTable[j]; i++){
        result.push(j)
      }
    }
  }
  return result
}

其他排序

此外还有冒泡排序,插入排序,希尔排序,基数排序(基数排序比较适合多位数排序,即每个数字都很大,有好几位数字)。