JavaScript 排序算法

116 阅读4分钟

minIndex 循环写法

let minIndex = (numbers) =>{
  let index = 0;                                                         
  for(let i = 1; i<numbers.length; i++){
    if(numbers[i]< numbers[index]){                           
    index = i                                                                 
    }
  }
  return index
}

每个数和下标[0]的数比,比下标[0]小的就记录下来为新的最小的数

选择排序 sort

循环写法思路
1)找到当前最小数的下标
2)最小数的下标和当前下标的数交换位置
3)swap(换位) JS析构赋值,可以交换数组的位置

let sort = (numbers) => {
  for(let i=0; i< numbers.length -1; i++){
    let index = minIndex(numbers.slice(i))+ i
    if(index!==i){swap(numbers, index, i)}
  }
  return numbers
}

let swap = (array, i, j) => {
  let temp = array[i]
  array[i] = array[j]
  array[j] = temp
}

let minIndex = (numbers) => {
  let index = 0
  for(let i=1; i<numbers.length; i++){
    if(numbers[i] < numbers[index]){
    index = i
    }
  }
  return index
}

选择排序,每次选最小或最大的,选完就排完
所有的递归都能写成循环,循环的边界条件不好确定,边界是length还是length-1

快速排序 quickSort

递归思路,以某某为基准
数组[12,3,7,21,5,9,4,6]
以21为基准,比它小的去左面,大的去右面;只需要重复这句话,就完成排序

let quickSort = arr =>{                                                        
  if(arr.length<=1){                                                          
    return arr;          
  }
  let pivotIndex = Math.floor(arr.length/2);                           
  let pivot = arr.splice(pivotIndex,1)[0];                                  
  let left =[];                                                                
  let right = [];
  for(let i=0; i<arr.length; i++){
    if(arr[i]<pivot){
      left.push(arr[i])
    }else{
    right.push(arr[i])
    }
  }
  return quickSort(left).concat([pivot],quickSort(right))          
}

quickSort快速排序,接收一个数组
如果这个数组长度小于1,直接返回这个数组
pivotIndex基准的索引,等于数组的长度除以2
floor地板(7除以2等于3.5,地板是3向下去最近的整数) 
pivot把基准单独拿出来,删除1项,返回删除的项是一个数组,加[0]会把第0项单独返回,不是数组
声明2个空数组,左边和右边
遍历删除基准之后的数组
如果arr[i]小于基准,把它放到左边数组,否则放在右边数组
左边进行快速排序concat(连接)基准,右边进行快速排序

归并排序 mergeSort

递归思路:不以某某为基准
数组[12,3,7,21,5,9,4,6]
左边一半排好序,右边一半排好序,然后把两边合并起来,就完成排序
把数组分成单个数字的数组,然后把每个数组合起来,就排好序了,因为单个数组默认是排好序的

let mergeSort = arr =>{
    let k = arr.length
    if(k === 1){
      return ar
    }
    let left = arr.slice(0,Math.floor(k/2)
    let right = arr.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(a.slice(1),b))                                         
}

mergeSort接收一个数组
k等于数组的长度
如果k等于1,直接返回这个数组
左边等于arr.slice(0,Math.floor(k/2))从arr的第0项开始,到2分之1
右边等于数组的另外2分之1
左边进行当前操作,右边进行当前操作,把数组分成单个数字的数组
左边排好序,右边排好序(实际上通过length=1,让数组变成单个数组,假装排好序,然后进行合并)
merge接收2个数组(a,b)(对每一项进行对比大小)
如果a的长度为0,数组为空,返回b
如果b的长度为0,数组为空,返回a
找出a,b数组中谁的第一位最小,如果a[0]>b[0],b[0]最小
那么就用b[0] 连接 a和b的其它部分的merge
a小的话,就a[0]连接 a除了0的其它部分,加数组b的merge  

计数排序 countSort

思路:用一个哈希表做记录
发现数字N,就记做N:1,如果再次发现N就加1
最后把哈希表的key全部打出来,假设N:M,那么N就打印M次

let countSort = arr =>{
    let hashTable = {}, max = 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){
            for(let i=0; i<hashTable[j]; i++){
                result.push(j)
            }
        }
    }
    return result
}

计数排序函数,接收一个数组
声明一个哈希表为空{},最大值为0,result为空数组
遍历数组
如果i不在哈希表里(!不在)
哈希表的第i个数=1
在进入一次数组,如果arr[i]在哈希表里,arr[i]=i+1
如果i>max,max等于i(记录最大的数,收集max)
遍历哈希表
如果j在哈希表里,就把j放到result里,返回result

如果j出现2次,在遍历一遍哈希表,拿到j的value,j的值是几,就push几次

计数排序特点,使用了额外的数据结构hashTable,只遍历一遍数组,不过还要遍历一遍hashTable
用空间换时间