排序算法(递归带图解)

200 阅读3分钟

实现简单Math.min

let min = (numbers) => {
    return numbers[0] > numbers[1] ? numbers[1] : numbers[0]
}
console.log(min.call(null, [9, 2]))//返回2
//现成API
Math.min(1,2)//1
Math.min.call(null,1,2)
Math.min.apply(null,[1,2])
//关于Math是首字母大写的对象
//看起来Math像Object一样是构造函数
//实际Math只是一个普通对象

返回数组最小数

//这是一个递归,当数组长度大于2时,调用自己,slice截取数组,不满足条件时进行对比,返回数组中的一个值进行对比
const min = (numbers) => {
  if (numbers.length > 2) {
    return min([numbers[0], min(numbers.slice(1))]);
  } else {
    return numbers[0] > numbers[1] ? numbers[1] : numbers[0];
  }
};
//任意长度数组的最小值

看图 递归求最小值

选择排序

递归
let numbers = [5,4,3,6,1,2]//一个无序的数组
let min = numbers =>{//一求最小值的函数
    return numbers.length > 2 ?min([numbers[0],min(numbers.slice(1))]):numbers[0]>numbers[1]?numbers[1]:numbers[0]
}
let sort = numbers => {
    if(numbers.length > 2){
        let index = numbers.indexOf(min(numbers))
        //从numbers里删除min(最小数)
        return numbers.splice(index,1).concat(sort(numbers))
    }else{
        return numbers[0] > numbers[1]?[numbers[1],numbers[0]]:numbers
    }
}

看图

循环

let numbers = [5, 4, 3, 6, 1, 2, 8 ,9]//一个无序的数组
let min = numbers => {//一求最小值的函数
    return numbers.length > 2 ? min([numbers[0], min(numbers.slice(1))]) : numbers[0] > numbers[1] ? numbers[1] : numbers[0]
}
let sort = (numbers) => {
    let len = numbers.length
    for (let i = 0; i < len; i++) {
        let index = numbers.indexOf(min(numbers.slice(i)))
        i !== index && swap(numbers, i, index)
    }
    return numbers
}

let swap = (numbers, index, i) => {
    let temp = numbers[i]
    numbers[i] = numbers[index]
    numbers[index] = temp
}
console.log(sort(numbers))
/*
循环数组
每次从更新的数组中找出最小的索引值并且返回 
拿到索引值后要写一个换值的函数
如果本身的索引值和返回值的索引值不相同则调用函数进行值的交换
*/

快速排序

let sort = (numbers)=>{
  if(numbers.length < 2){return numbers;}
  let pivot = numbers.splice(Math.floor(numbers.length/2),1)[0];
  let left = [],right = []
  numbers.map(item=>item>pivot?right.push(item):left.push(item))
  return sort(left).concat([pivot],sort(right))
}
/*快速排序
先获得一个基准位置的索引值,一般从中间取一个基准数
声明两个空列表,一个左一个右
循环列表和基准的数字对比较,对比其大小分别push进左或右的空数组 
返回值为递归调用左边数组扩展右边的数组包含提取出来的基准数组,这里的基准数组要加[]*/

快速排序

归并排序

下面就不画图了,太累

let mergesort = (numbers)=>{
  let k=numbers.length
  if(k===1){return numbers}
  let left = numbers.slice(0,Math.floor(k/2))
  let right = numbers.slice(Math.floor(k/2))
  return merge(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(b,a.slice(1)))
}
/*
创建一个函数,接收一个数组,
声明一个变量获得数组的长度
如果长度为1,返回数组
声明一个left数组变量(长度为从数组左边起的一半,也就是数组的前半段
声明一个right数组变量(长度为从数组右边起的一半,也就数组的后半段
返回值设置为 给merge函数传递两个参数,而传递的两个参数(left和right)各自调用mergesort进行递归,将整个数组分解成一个个的单一小数组
merge函数接收两个数组如果其中一个数组长度为0则返回另一个数组
merge函数返回值是 对比两个数组中为索引为0的数,然后对比大小返回一个新数组
*/

计数排序

let numbers = [5, 4, 3, 6, 1, 2]//一个无序的数组
let countSort = (numbers)=>{
    let hashTable ={},max = 0,result=[];
    for(let i=0;i<numbers.length;i++){
      if(!(numbers[i] in hashTable)){
        hashTable[numbers[i]] = 1
      }else{
        hashTable[numbers[i]] +=1
      }
      if(numbers[i]>max){
        max = numbers[i]
      }
    }
    for(let j =0;j<=max;j++){
      if(j in hashTable){
        for(let i = 0;i<hashTable[j];i++){//去掉这一句可以每个元素只添加一次
          result.push(j)
        }
      }
    }
    return result
  }
console.log(countSort(numbers))
 /*
 声明一个哈希表
一个空数组
遍历整个数组,给出现的值计数,同时找出最大的数
遍历整个哈希表,用最大的值做循环范围,将元素按顺序添加进*/