选择排序和快速排序

181 阅读3分钟

关于Math.min

JS内置了Math.min(可以直接使用),用来输出两个数之间的最小值。

  • math.min(1,2) //1
  • Math.min.call(null,1,2)
  • math.min.apply(null,1,2)

注:一般来说,首字母大写的是构造函数,Math实际上只是一个普通对象,这是唯一的一个特例。

选择排序

1.webp

递归实现选择排序的思路

  1. 假定数组中的第一个元素a为最小值,其余的所有元素组成的新数组记为B
  2. 然后通过min的实现找到B的最小值记为c
  3. 此时数组只剩下了元素a和c,两个元素的比较可以通过Math.min.apply得到整个数组的最小值
  4. minIndex可以获取最小值的下标
  5. 剩下的元素重复操作,每次得到一个最小值最为新的数组,余下元素一直重复,直至完成排序。

一句话总结:每次找到最小的数放前面,然后对后面的数做同样的事情。

用递归的思想实现选择排序

let sort = (numbers) => {
  if(numbers.length > 2){
    let index = minIndex(numbers)  //获取最小值的下标
    let min = numbers[index]          //将最小值命名为min
    numbers.splice(index, 1)           //从数组中删除最小值
    return [min].concat(sort(numbers))  //最小值作为一个新数组和后面的循环操作的得到数组连接成一个新数组。
    }else{
    //数组长度小于等于2 时的操作:原样输出或者换位输出。
    return numbers[0]<numbers[1] ? numbers :   
           numbers.reverse()  
  }
}
     //minIndex的实现,获取数组最小值的下标
let minIndex = (numbers) =>
  numbers.indexOf(min(numbers))  
         //min的实现,获取数组中的最小值
let min = (numbers) => {
  if(numbers.length > 2){
    return min(
      [numbers[0], min(numbers.slice(1))]
    )
  }else{     数组长度小于2时 用JS内置的Math.min.apply来的到数组最小值。
    return Math.min.apply(null, numbers)   
  }
}

用循环实现选择排序

let sort = (numbers) => {
  for(let i=0; i< numbers.length -1; i++){
    console.log(`----`)                           //这个log很精髓,可以区分出每一次的换位操作
    let index = minIndex(numbers.slice(i))+ i
    if(index!==i){
      swap(numbers, index, i)
    }
}
  return numbers
}
      //实现换位
let swap = (numbers, i, j) => {
  let temp = numbers[i]
 numbers[i] = numbers[j]
  numbers[j] = temp
}
    //获取最小元素的下标
let minIndex = (numbers) => {
  let index = 0                              //假定下标为0(第一个元素)的值是最小的
  for(let i=1; i<numbers.length; i++){       //因为下标为0的已经假定为目前的最小值了,所以后面的循环比较先从下标1和下标0对比,再i++
    if(numbers[i] < numbers[index]){         //每一次比较,值小的作为index 从而得到最小值的下标
      index = i
    }
  }
  return index                              
}

快速排序

每个(未排序)的部分

将第一个元素设为 pivot

存储索引 = pivot索引 +1

从 i=pivot指数 +1 到 最右索引 的遍历

如果 a[i] < a[pivot]

交换 (i, 存储索引); 存储索引++;

交换(pivot, 存储索引 - 1)

11.webp

代码实现

let quickSort = arr => {
         //数组元素小于等于1 就不用排序了 直接输出
  if (arr.length <= 1) { return arr; }
  let pivotIndex = Math.floor(arr.length / 2);  //设置基准的位置
  let pivot = arr.splice(pivotIndex, 1)[0];   //得到基准 因为splic返回的是    
                                        //被删掉的那个元素自己作为一个新数组,为了未得到元素 加[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) )
}

总的来说,快速排序就是自己设定一个基准(上面的代码是把数组的中间元素设为基准),作为每个基准的值在此轮排序中位置保持不变,比基准的值小的放左边,比基准的值大的放右边。

然后在左右两边的数组重复上面的操纵,最后左+基准+右来实现排序。

点击链接可以查看排序过程图:

排序(冒泡排序,选择排序,插入排序,归并排序,快速排序,计数排序,基数排序) - VisuAlgo