数据排序

148 阅读2分钟

总的来说,数组的排列方式分为循环排列和递归排列,所有的递归排列都能用循环排列替换。下面来一一具体举例数组的排列方法:

1.选择排序

运行下面代码,输入一个sort()

let sort = (arr) => {
    if (arr.length > 2) {
        let index = minIndex(arr)
        let min = arr[index]
        arr.splice(index, 1)
        return [min].concat(sort(arr))
    } else {
        return arr[0] < arr[1] ? arr : arr.reverse()
    }
}
let minIndex = (arr) => {
    return arr.indexOf(min(arr))
}
let min = (arr) => {
    if (arr.length > 2) {
        return min(
            [arr[0], min(arr.slice(1))]
        )
    } else {
        return Math.min.apply(null, arr)
    }
}

代码中的选择排序就是每次将数组中最小值min的角标minIndex找出来,然后splice掉它,再[min].concat(sort(arr)),但这样会导致无限循环下去,所以要加个arr.length>2的条件,递归到直至完成

改成for循环的写法如下:

let sort = arr => {
    for (let i = 0; i < arr.length; i++) {
        let index = minIndex(arr.slice(i)) + i
        if (index !== i) {
            swap(arr, i, index)
            console.log(`swap:${i},${index}`)
        }
        console.log(`${arr}`)
        console.log(`---`)
        //consoe.log调试大法
    }
    return arr
}
//上面是思考的过程,达到目的的方式

let minIndex = arr => {
    let index = 0
    for (let i = 1; i < arr.length; i++) {
        if (arr[index] > arr[i]) {
            index = i
            //这里index = i 前面不能有 return
        }
    }
    return index
}
//这是定义minIndex

let swap = (arr, i, j) => {
    let temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}
//这是定义swap

这种方法就是先遍历出最小值的index,在与当前for下的i比较,如果index !== i则交换arr[index]与arr[i]的值,一直循环到最后两位数进行比较,得到排列后的arr

2.快速排序

快速排序就一个特点,代码简单,容易理解

栗子

let quickSort = arr => {
    if (arr.length <= 1) { return arr }
    let halfIndex = Math.floor(arr.length / 2)
    //找到中间的index
    let left = []
    let right = []
    let half = arr[halfIndex]
    arr.splice(halfIndex, 1)
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < half) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return quickSort(left).concat([half], quickSort(right))
    //这一步是精髓,让left,right再次quickSort()循环

将数组均分,得到arr.length/2的值,比这个值小的放到left里面去,比这个值大的放到right里面去,最后的return是精髓,再次用到递归排序。

3.归并排序

归并排序是较难理解的一种递归排序方法

let mergeSort = arr => {
    if (arr.length === 1) { return arr }
    let left = arr.slice(0, Math.floor(arr.length / 2))
    let right = arr.slice(Math.floor(arr.length / 2))
    return merge(mergeSort(left), mergeSort(right))
}
let merge = (a, b) => {
    if (a.length === 0) { return b }
    if (b.length === 0) { return a }
    console.log(`${a}::${b}`)
    console.log(`---`)
    return a[0] > b[0] ? [b[0]].concat(merge(a, b.slice(1))) : [a[0]].concat(merge(a.slice(1), b))
}

也是将数组分成左右两半,左半部分再分左右,右半部分再分左右,直到分成每个组里就一个数字,再merge,难理解的地方也在merge这里,两两比较,取两者第一个数字中小的那个出来,再次循环merge

4.计数排序

计数排序运用到了哈希表,大大节省了排序时间。

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
}

5.冒泡排序

排序时间较长,但使用内存较小,排序逻辑也简单。

let arr=[4,3,12,1,3,8,-2]
function bubbleSort(arr){
  for(let j=0;j<arr.length-1;j++){
    let done=true
    for (let i=0;i<arr.length-1-j;i++){
      if (arr[i]>arr[i+1]){
        const tem=arr[i]
        arr[i]=arr[i+1]
        arr[i+1]=tem
        done=false
      }
    }
    if(done){
        break;
    }
  }
  return arr
}
bubbleSort(arr)
console.log(arr)

6.插入排序

插入排序后者小于前者,后者就依次向前排,复杂度与冒泡排序一样。

function insertSort(arr){
  for(let i=1;i<arr.length;i++){
    let temp=arr[i]
    let j
    for(j=i;j>0;j--){
      if(temp>=arr[j-1]){
        break;
      }
      arr[j]=arr[j-1]
    }
    arr[j]=temp
  }
  return arr
}

7.其他排序

基数排序希尔排序***

这些排序平时用的并不多,就不一一列举了。

数组排序复杂度

**时间复杂度:**是指排序算法所耗时间;

**空间复杂度:**也就是指排序过程中所占用的内存大小;

**稳定性:**所谓稳定性是指待排序的序列中有两元素相等,排序之后它们的先后顺序不变。